diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-00cecdb4dc8514ec7e775622bc723648.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-00cecdb4dc8514ec7e775622bc723648.json new file mode 100644 index 0000000..0f7db0d --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-00cecdb4dc8514ec7e775622bc723648.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Loading\u2026":["Cargando..."]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/base\/components\/loading-mask\/index.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-01739590876f3ab645ec3678e42bbc29.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-01739590876f3ab645ec3678e42bbc29.json new file mode 100644 index 0000000..a9bd00b --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-01739590876f3ab645ec3678e42bbc29.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Link to":["Enlace a"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/editor-components\/page-selector\/index.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-01b768ae1db405a69d13758eda43a58b.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-01b768ae1db405a69d13758eda43a58b.json new file mode 100644 index 0000000..1499138 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-01b768ae1db405a69d13758eda43a58b.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"This product is currently out of stock and cannot be purchased.":["Este producto actualmente no tiene existencias y no puede comprarse."],"View Product":["Ver producto"],"Select an option":["Selecciona una opci\u00f3n"],"Please select a value.":["Por favor, selecciona un valor."],"Something went wrong. Please contact us to get assistance.":["Algo ha salido mal. Por favor, cont\u00e1ctanos para obtener ayuda."],"%d in cart":["%d en el carrito","%d en el carrito"],"Done":["Hecho"],"Sorry, this product cannot be purchased.":["Lo sentimos, este producto no se puede comprar."],"Add to cart":["A\u00f1adir al carrito"]}},"comment":{"reference":"packages\/woocommerce-blocks\/build\/atomic-block-components\/add-to-cart-frontend.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-02acd74879196411261af7576fdb4b93.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-02acd74879196411261af7576fdb4b93.json new file mode 100644 index 0000000..3778d1d --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-02acd74879196411261af7576fdb4b93.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"The last inner block will follow other content.":["El \u00faltimo bloque interior seguir\u00e1 al resto del contenido."],"The last inner block will be aligned vertically.":["El \u00faltimo bloque interior se alinear\u00e1 verticalmente"],"Align Last Block":["Alinear \u00faltimo bloque"],"Product Tags":["Etiquetas del producto"],"This block displays products from selected tags. In order to preview this you'll first need to create a product and assign it some tags.":["Este bloque muestra productos de las etiquetas seleccionadas. Para previsualizarlo primero tienes que crear un producto y asignarle alguna etiqueta."],"This block displays products from selected tags. Select at least one tag to display its products.":["Este bloque muestra productos de las etiquetas seleccionadas. Selecciona al menos una etiqueta para mostrar sus productos."],"Done":["Hecho"],"Showing Products by Tag block preview.":["Mostrando la vista previa del bloque de productos por etiqueta."],"Products by Tag":["Productos por etiqueta"],"Order By":["Ordenar por"],"Layout":["Estructura"],"Rows":["Filas"],"Add to Cart button is hidden.":["El bot\u00f3n de a\u00f1adir al carrito est\u00e1 oculto."],"Columns":["Columnas"],"Add to Cart button is visible.":["El bot\u00f3n de a\u00f1adir al carrito es visible."],"Add to Cart button":["Bot\u00f3n de a\u00f1adir al carrito"],"Display a grid of products from your selected tags.":["Muestra una cuadr\u00edcula de productos de las etiquetas que selecciones."],"Display a grid of products with selected tags.":["Muestra una cuadr\u00edcula de productos con las etiquetas seleccionadas."],"Menu Order":["Orden del men\u00fa"],"Title - alphabetical":["T\u00edtulo - alfab\u00e9tico"],"Sales - most first":["Ventas - primero los m\u00e1s vendidos"],"Rating - highest first":["Valoraci\u00f3n - primero los mejores"],"Price - high to low":["Precio - de mayor a menor"],"Price - low to high":["Precio - de menor a mayor"],"Newness - newest first":["Novedad - primero los m\u00e1s nuevos"],"Order products by":["Ordenar productos por"],"All selected tags":["Todas las etiquetas seleccionadas"],"Any selected tags":["Cualquier etiqueta seleccionada"],"Pick at least two tags to use this setting.":["Elige al menos dos etiquetas para usar este ajuste."],"Display products matching":["Mostrar productos que coincidan"],"Tag search results updated.":["Resultados de b\u00fasqueda de etiqueta actualizados."],"%d tag selected":["%d etiqueta seleccionada","%d etiquetas seleccionadas"],"Search for product tags":["Buscar por etiquetas de productos"],"Your store doesn't have any product tags.":["Tu tienda no tiene ninguna etiqueta de producto."],"Clear all product tags":["Vaciar todas las etiquetas de producto"],"Product rating is hidden.":["La valoraci\u00f3n del producto est\u00e1 oculta."],"Product rating is visible.":["La valoraci\u00f3n del producto es visible."],"Product rating":["Valoraci\u00f3n del producto"],"Product price is hidden.":["El precio del producto est\u00e1 oculto."],"Product price is visible.":["El precio del producto es visible."],"Product price":["Precio del producto"],"Product title is hidden.":["El t\u00edtulo del producto est\u00e1 oculto."],"Product title is visible.":["El t\u00edtulo del producto es visible."],"Product title":["T\u00edtulo del producto"],"%1$d product tagged as %2$s":["%1$d producto etiquetado como %2$s","%1$d productos etiquetados como %2$s"],"Content":["Contenido"],"Cancel":["Cancelar"],"Product Tag":["Etiquetas de producto"],"WooCommerce":["WooCommerce"],"Edit":["Editar"]}},"comment":{"reference":"packages\/woocommerce-blocks\/build\/product-tag.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-0436417c01a5fcf6da938f5082798846.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-0436417c01a5fcf6da938f5082798846.json new file mode 100644 index 0000000..409e402 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-0436417c01a5fcf6da938f5082798846.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Choose which leaderboards to display and other settings":["Elige qu\u00e9 favoritos mostrar y otros ajustes"],"Leaderboards":["Favoritos"],"Rows Per Table":["Filas por tabla"],"No data recorded for the selected time period.":["No hay datos almacenados del periodo de tiempo seleccionado."],"View Orders":["Ver pedidos"],"No results could be found for this date range.":["No se han encontrado resultados en este rango de fechas."],"Reload":["Recargar"],"There was an error getting your stats. Please try again.":["Hubo un error al recuperar tus estad\u00edsticas. Por favor, int\u00e9ntalo de nuevo."]}},"comment":{"reference":"packages\/woocommerce-admin\/dist\/chunks\/leaderboards.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-056e3f14efed538fde21950202add8dc.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-056e3f14efed538fde21950202add8dc.json new file mode 100644 index 0000000..d1ae5b6 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-056e3f14efed538fde21950202add8dc.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Visually highlight a product or variation and encourage prompt action.":["Destaca visualmente un producto o una variaci\u00f3n y anima a realizar una acci\u00f3n."],"Shop now":["Comprar ahora"],"Featured Product":["Producto destacado"],"WooCommerce":["WooCommerce"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/blocks\/featured-product\/index.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-0657952e8fe472b7a7f031ef6c2f1e6a.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-0657952e8fe472b7a7f031ef6c2f1e6a.json new file mode 100644 index 0000000..e554df5 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-0657952e8fe472b7a7f031ef6c2f1e6a.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Choose a product to display its add to cart button.":["Elige un producto para mostrar su bot\u00f3n de a\u00f1adir al carrito."]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/atomic\/blocks\/product-elements\/button\/edit.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-09444bf964f9242a7dc345c5da29c237.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-09444bf964f9242a7dc345c5da29c237.json new file mode 100644 index 0000000..ccbf8ed --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-09444bf964f9242a7dc345c5da29c237.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Add a note to your order":["A\u00f1ade una nota a tu pedido"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/blocks\/cart-checkout\/checkout\/form\/order-notes\/index.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-09b8a04693848711e3459fcc6f5f2a94.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-09b8a04693848711e3459fcc6f5f2a94.json new file mode 100644 index 0000000..997c668 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-09b8a04693848711e3459fcc6f5f2a94.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Display the main product image":["Mostrar la imagen principal del producto"],"Product Image":["Imagen del producto"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/atomic\/blocks\/product-elements\/image\/constants.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-09c5919a18291dd26d6f52f9d1563a8e.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-09c5919a18291dd26d6f52f9d1563a8e.json new file mode 100644 index 0000000..a22cfd5 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-09c5919a18291dd26d6f52f9d1563a8e.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Fly your WordPress banner with this beauty! Deck out your office space or add it to your kids walls. This banner will spruce up any space it\u2019s hung!":["\u00a1Despliega tu estandarte de WordPress con esta belleza! Decora tu oficina o a\u00f1\u00e1dela a las paredes de tus hijos. \u00a1Esta banderola aderezar\u00e1 cualquier espacio en el que se cuelgue!"],"Add to cart":["A\u00f1adir al carrito"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/previews\/products.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-0a3b65850c50f16de824a40fa5ff0f0f.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-0a3b65850c50f16de824a40fa5ff0f0f.json new file mode 100644 index 0000000..446659f --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-0a3b65850c50f16de824a40fa5ff0f0f.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Filter by Product Category":["Filtrar por categor\u00eda de producto"],"Layout":["Estructura"],"Content":["Contenido"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/blocks\/product-new\/block.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-0cf7579f6fbc3a394bde81590518d79e.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-0cf7579f6fbc3a394bde81590518d79e.json new file mode 100644 index 0000000..50f7ee6 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-0cf7579f6fbc3a394bde81590518d79e.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"The following error was returned":["Se devolvi\u00f3 el siguiente error"],"This product is awesome, I love it!":["Este producto es asombroso, \u00a1me encanta!"],"Bob":["Roberto"],"July 12, 2019":["12 de julio de 2019"],"I bought this product last week and I'm very happy with it.":["Compr\u00e9 este producto la semana pasada y estoy muy feliz con \u00e9l."],"Alice":["Alicia"],"WordPress Pennant":["Bander\u00edn de WordPress"],"July 15, 2019":["15 de julio de 2019"],"This block shows a list of all product reviews. Your store does not have any reviews yet, but they will show up here when it does.":["Este bloque muestra una lista de todas las valoraciones de productos. Tu tienda todav\u00eda no tiene valoraciones, pero se mostrar\u00e1n aqu\u00ed cuando las tenga."],"Load more reviews":["Cargar m\u00e1s valoraciones"],"Sorry, an error occurred":["Lo siento, ha ocurrido un error"],"The following error was returned from the API":["El siguiente error ha sido devuelto desde la API"],"An unknown error occurred which prevented the block from being updated.":["Ha ocurrido un error desconocido que ha impedido que el bloque haya sido actualizado."],"All Reviews":["Todas las valoraciones"],"Retry":["Volver a intentar"],"Show a list of all product reviews.":["Muestra una lista de todas las valoraciones de productos."],"Starting Number of Reviews":["N\u00famero inicial de valoraciones"],"Load More Reviews":["Cargar m\u00e1s valoraciones"],"Reviewer name":["Nombre de quien valora"],"Review date":["Fecha de la valoraci\u00f3n"],"Review content":["Contenido de la valoraci\u00f3n"],"Review image":["Imagen de la valoraci\u00f3n"],"Reviewer photo":["Foto de quien valora"],"Order Product Reviews by":["Ordenar las valoraciones de los productos por"],"The content for this block is hidden due to block settings.":["El contenido de este bloque est\u00e1 oculto debido a los ajustes del bloque."],"Most recent":["Las m\u00e1s recientes"],"Verified buyer":["Comprador verificado"],"Read full review":["Leer la valoraci\u00f3n completa"],"Hide full review":["Ocultar la valoraci\u00f3n completa"],"Read less":["Leer menos"],"Load more":["Cargar m\u00e1s"],"Highest rating":["La mayor valoraci\u00f3n"],"Lowest rating":["La menor valoraci\u00f3n"],"Order reviews by":["Ordenar las valoraciones por"],"Product rating is disabled in your store settings<\/a>.":["La valoraci\u00f3n de productos est\u00e1 desactivada en tus ajustes de la tienda<\/a>."],"Reviewer photo is disabled in your site settings<\/a>.":["La foto de quien valora est\u00e1 desactivada en tus ajustes del sitio<\/a>."],"List Settings":["Ajustes de la lista"],"Product rating":["Valoraci\u00f3n del producto"],"Rated %f out of 5":["Valorado con %f de 5"],"Content":["Contenido"],"Image":["Imagen"],"Product name":["Nombre del producto"],"WooCommerce":["WooCommerce"],"Order by":["Ordenar por"],"Edit":["Editar"],"Product":["Producto"],"Read more":["Leer m\u00e1s"]}},"comment":{"reference":"packages\/woocommerce-blocks\/build\/all-reviews.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-0db65848d165e94c1b721836932fa2b2.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-0db65848d165e94c1b721836932fa2b2.json new file mode 100644 index 0000000..6666527 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-0db65848d165e94c1b721836932fa2b2.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"This product is currently out of stock and cannot be purchased.":["Este producto actualmente no tiene existencias y no puede comprarse."]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/atomic\/blocks\/product-elements\/add-to-cart\/product-types\/simple.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-0dc089127d6d4abad378c797b27b1007.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-0dc089127d6d4abad378c797b27b1007.json new file mode 100644 index 0000000..7a808c3 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-0dc089127d6d4abad378c797b27b1007.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Text color":["Color de texto"],"Color settings":["Ajustes de color"],"Choose a product to display its title.":["Elige un producto para mostrar su t\u00edtulo."],"Links the image to the single product listing.":["Enlaza la imagen al listado de un producto."],"Link to Product Page":["Enlace a la p\u00e1gina del producto"],"Content":["Contenido"],"Text settings":["Ajustes de texto"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/atomic\/blocks\/product-elements\/title\/edit.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-0e3dcd4f3ff5aa786acbbd18de58d420.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-0e3dcd4f3ff5aa786acbbd18de58d420.json new file mode 100644 index 0000000..2b94e4c --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-0e3dcd4f3ff5aa786acbbd18de58d420.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"%1$s, has %2$d product":["%1$s, tiene %2$d producto","%1$s, tiene %2$d productos"],"%1$s, has %2$d review":["%1$s, tiene %2$d valoraci\u00f3n","%1$s, tiene %2$d valoraciones"],"The last inner block will follow other content.":["El \u00faltimo bloque interior seguir\u00e1 al resto del contenido."],"The last inner block will be aligned vertically.":["El \u00faltimo bloque interior se alinear\u00e1 verticalmente"],"Align Last Block":["Alinear \u00faltimo bloque"],"%d Product":["%d producto","%d productos"],"The following error was returned":["Se devolvi\u00f3 el siguiente error"],"%d Review":["%d valoraci\u00f3n","%d valoraciones"],"The following error was returned from the API":["El siguiente error ha sido devuelto desde la API"],"An unknown error occurred which prevented the block from being updated.":["Ha ocurrido un error desconocido que ha impedido que el bloque haya sido actualizado."],"Display a grid of your newest products.":["Muestra una cuadr\u00edcula de productos m\u00e1s recientes."],"Newest Products":["Productos m\u00e1s recientes"],"Filter by Product Category":["Filtrar por categor\u00eda de producto"],"All selected categories":["Todas las categor\u00edas seleccionadas"],"Any selected categories":["Cualquier categor\u00eda seleccionada"],"Pick at least two categories to use this setting.":["Elige al menos dos categor\u00edas para usar este ajuste."],"Category search results updated.":["Resultados de b\u00fasqueda de categor\u00eda actualizados."],"%d category selected":["%d categor\u00eda seleccionada","%d categor\u00edas seleccionadas"],"Search for product categories":["Buscar por categor\u00edas de producto"],"Your store doesn't have any product categories.":["Tu tienda no tiene ninguna categor\u00eda de producto."],"Clear all product categories":["Vaciar todas las categor\u00edas de producto"],"Layout":["Estructura"],"Rows":["Filas"],"Add to Cart button is hidden.":["El bot\u00f3n de a\u00f1adir al carrito est\u00e1 oculto."],"Columns":["Columnas"],"Add to Cart button is visible.":["El bot\u00f3n de a\u00f1adir al carrito es visible."],"Add to Cart button":["Bot\u00f3n de a\u00f1adir al carrito"],"Display products matching":["Mostrar productos que coincidan"],"Product rating is hidden.":["La valoraci\u00f3n del producto est\u00e1 oculta."],"Product rating is visible.":["La valoraci\u00f3n del producto es visible."],"Product rating":["Valoraci\u00f3n del producto"],"Product price is hidden.":["El precio del producto est\u00e1 oculto."],"Product price is visible.":["El precio del producto es visible."],"Product price":["Precio del producto"],"Product title is hidden.":["El t\u00edtulo del producto est\u00e1 oculto."],"Product title is visible.":["El t\u00edtulo del producto es visible."],"Product title":["T\u00edtulo del producto"],"Content":["Contenido"],"Product Categories":["Categor\u00edas de producto"],"WooCommerce":["WooCommerce"]}},"comment":{"reference":"packages\/woocommerce-blocks\/build\/product-new.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-11eaf0a60d602f142e96c14c44445c1c.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-11eaf0a60d602f142e96c14c44445c1c.json new file mode 100644 index 0000000..34c766f --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-11eaf0a60d602f142e96c14c44445c1c.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Return to Cart":["Volver al carrito"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/base\/components\/cart-checkout\/return-to-cart-button\/index.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-124cfb7a5d89d9c89c181e1d53e04227.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-124cfb7a5d89d9c89c181e1d53e04227.json new file mode 100644 index 0000000..ec538fb --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-124cfb7a5d89d9c89c181e1d53e04227.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"This block displays products from selected tags. In order to preview this you'll first need to create a product and assign it some tags.":["Este bloque muestra productos de las etiquetas seleccionadas. Para previsualizarlo primero tienes que crear un producto y asignarle alguna etiqueta."],"This block displays products from selected tags. Select at least one tag to display its products.":["Este bloque muestra productos de las etiquetas seleccionadas. Selecciona al menos una etiqueta para mostrar sus productos."],"Done":["Hecho"],"Showing Products by Tag block preview.":["Mostrando la vista previa del bloque de productos por etiqueta."],"Products by Tag":["Productos por etiqueta"],"Order By":["Ordenar por"],"Layout":["Estructura"],"Display a grid of products from your selected tags.":["Muestra una cuadr\u00edcula de productos de las etiquetas que selecciones."],"Content":["Contenido"],"Cancel":["Cancelar"],"Product Tag":["Etiquetas de producto"],"Edit":["Editar"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/blocks\/product-tag\/block.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-12698f76de1361156158b68e7449b0a9.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-12698f76de1361156158b68e7449b0a9.json new file mode 100644 index 0000000..74abb88 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-12698f76de1361156158b68e7449b0a9.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Add %s section":["A\u00f1adir secci\u00f3n %s"],"Dashboard Sections":["Secciones del escritorio"],"Add more sections":["A\u00f1adir m\u00e1s secciones"],"Remove section":["Quitar secci\u00f3n"],"Remove block":["Quitar bloque"],"Move Down":["Bajar"],"Performance":["Rendimiento"],"Section Title":["T\u00edtulo de la secci\u00f3n"],"Leaderboards":["Favoritos"],"Charts":["Gr\u00e1ficos"],"Move up":["Subir"]}},"comment":{"reference":"packages\/woocommerce-admin\/dist\/chunks\/customizable-dashboard.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-154eb5541053115f9cf2cc279decf649.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-154eb5541053115f9cf2cc279decf649.json new file mode 100644 index 0000000..acd0b0b --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-154eb5541053115f9cf2cc279decf649.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"This block lists reviews for products from selected categories. The selected categories do not have any reviews yet, but they will show up here when they do.":["Este bloque lista las valoraciones de los productos de las categor\u00edas seleccionadas. Las categor\u00edas seleccionadas todav\u00eda no tienen valoraciones, pero se mostrar\u00e1n aqu\u00ed cuando las tengan."],"Reviews by Category":["Valoraciones por categor\u00eda"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/blocks\/reviews\/reviews-by-category\/no-reviews-placeholder.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-15ffb2e3ba27c86287dde1e4045e79cc.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-15ffb2e3ba27c86287dde1e4045e79cc.json new file mode 100644 index 0000000..873ad6f --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-15ffb2e3ba27c86287dde1e4045e79cc.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Choose which analytics to display and the section name":["Elige qu\u00e9 an\u00e1lisis mostrar y el nombre de la secci\u00f3n"],"Display Stats:":["Mostrar estad\u00edsticas:"],"Store Performance":["Rendimiento de la tienda"],"Previous Year:":["A\u00f1o anterior:"],"Previous Period:":["Periodo anterior:"]}},"comment":{"reference":"packages\/woocommerce-admin\/dist\/chunks\/store-performance.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1605a532b87cc989e30f0c39532c5845.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1605a532b87cc989e30f0c39532c5845.json new file mode 100644 index 0000000..be1cac4 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1605a532b87cc989e30f0c39532c5845.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Sorry, this product cannot be purchased.":["Lo sentimos, este producto no se puede comprar."]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/atomic\/blocks\/product-elements\/add-to-cart\/shared\/product-unavailable.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-16268754aba0e39aeb4f24c835d52820.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-16268754aba0e39aeb4f24c835d52820.json new file mode 100644 index 0000000..6297971 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-16268754aba0e39aeb4f24c835d52820.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Display a single product.":["Mostrar un producto individual."],"Single Product":["Producto individual"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/blocks\/single-product\/constants.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1869430a90f07a7364b4c043829f725f.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1869430a90f07a7364b4c043829f725f.json new file mode 100644 index 0000000..34119c4 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1869430a90f07a7364b4c043829f725f.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Categories:":["Categor\u00edas:"]}},"comment":{"reference":"packages\/woocommerce-blocks\/build\/atomic-block-components\/category-list-frontend.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-18a31075fa5f4596edaf76ec78921ff4.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-18a31075fa5f4596edaf76ec78921ff4.json new file mode 100644 index 0000000..5571ce9 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-18a31075fa5f4596edaf76ec78921ff4.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"%1$s, has %2$d review":["%1$s, tiene %2$d valoraci\u00f3n","%1$s, tiene %2$d valoraciones"],"Showing Reviews by Product block preview.":["Mostrando la vista previa del bloque de valoraciones por producto."],"Show reviews of your product to build trust":["Muestra las valoraciones de tus productos para crear confianza"],"%d Review":["%d valoraci\u00f3n","%d valoraciones"],"Reviews by Product":["Valoraciones por producto"],"List Settings":["Ajustes de la lista"],"Done":["Hecho"],"Content":["Contenido"],"Product":["Producto"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/blocks\/reviews\/reviews-by-product\/edit.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-19f16f4fc69aa97ecde5d39d523dfd8b.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-19f16f4fc69aa97ecde5d39d523dfd8b.json new file mode 100644 index 0000000..ee12887 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-19f16f4fc69aa97ecde5d39d523dfd8b.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"CVV\/CVC":["CVV\/CVC"],"Expiry Date":["Fecha de caducidad"],"Card Number":["N\u00famero de la tarjeta"],"Credit Card Information":["Informaci\u00f3n de la tarjeta de cr\u00e9dito"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/payment-method-extensions\/payment-methods\/stripe\/credit-card\/elements.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-19f52ef80d162b0ab094ab96c60a76e8.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-19f52ef80d162b0ab094ab96c60a76e8.json new file mode 100644 index 0000000..d5db413 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-19f52ef80d162b0ab094ab96c60a76e8.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"%d in cart":["%d en el carrito","%d en el carrito"],"Add to cart":["A\u00f1adir al carrito"]}},"comment":{"reference":"packages\/woocommerce-blocks\/build\/atomic-block-components\/button.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1a349548a3d38de6f8013f63a02ddf4b.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1a349548a3d38de6f8013f63a02ddf4b.json new file mode 100644 index 0000000..5f88dff --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1a349548a3d38de6f8013f63a02ddf4b.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Remove coupon \"%s\"":["Eliminar cup\u00f3n \u00ab%s\u00bb"],"Removing coupon\u2026":["Eliminando cup\u00f3n\u2026"],"Coupon: %s":["Cup\u00f3n: %s"],"Discount":["Descuento"],"Coupons":["Cupones"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/base\/components\/cart-checkout\/totals\/totals-discount-item\/index.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1ab3c5ff6a861a0bbc5e57811248de9b.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1ab3c5ff6a861a0bbc5e57811248de9b.json new file mode 100644 index 0000000..782ca16 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1ab3c5ff6a861a0bbc5e57811248de9b.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Apply price filter":["Aplicar el filtro de precios"],"Apply filter":["Aplicar filtro"],"Filter products by maximum price":["Filtrar productos por mayor precio"],"Filter products by minimum price":["Filtrar productos por el menor precio"],"Oops!":["\u00a1Vaya!"],"There was an error loading the content.":["Ha habido un error al cargar este contenido."],"Error:":["Error:"],"Go":["Ir"],"Price":["Precio"]}},"comment":{"reference":"packages\/woocommerce-blocks\/build\/price-filter-frontend.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1b3f299878731ed7e1fc34722ef3c267.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1b3f299878731ed7e1fc34722ef3c267.json new file mode 100644 index 0000000..25005f7 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1b3f299878731ed7e1fc34722ef3c267.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"example product in Cart Block\u0004Beanie":["Gorro"],"example product in Cart Block\u0004Beanie with Logo":["Gorra con logotipo"],"Free shipping":["Env\u00edo gratuito"],"Shipping":["Env\u00edo"],"Local pickup":["Recogida local"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/previews\/shipping-rates.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1b59d077cd5a766feef182aa33bfdeb6.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1b59d077cd5a766feef182aa33bfdeb6.json new file mode 100644 index 0000000..72327bb --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1b59d077cd5a766feef182aa33bfdeb6.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Filter button":["Bot\u00f3n de filtrado"],"Editable":["Editable"],"Price Range":["Rango de precios"],"Products with prices are needed for filtering by price. You haven't created any products yet.":["Para filtrar por precio, se necesitan productos con precio. Todav\u00eda no has creado ning\u00fan producto."],"Products will update when the slider is moved.":["Los productos se actualizar\u00e1n cuando se mueva el carrusel."],"Products will only update when the button is pressed.":["Los productos solo se actualizar\u00e1n cuando se presione el bot\u00f3n."],"Block Settings":["Ajustes del bloque"],"Heading Level":["Nivel del encabezado"],"Filter Products by Price":["Filtrar productos por precio"],"Display a slider to filter products in your store by price.":["Muestra un control deslizante para filtrar productos de tu tienda por precio."],"Text":["Texto"],"Add new product":["A\u00f1adir nuevo producto"],"Learn more":["Aprende m\u00e1s"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/blocks\/price-filter\/edit.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1b8267223028487f1ab7e31c03738ca0.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1b8267223028487f1ab7e31c03738ca0.json new file mode 100644 index 0000000..925ba33 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1b8267223028487f1ab7e31c03738ca0.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"WooCommerce":["WooCommerce"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/atomic\/blocks\/product-elements\/shared\/config.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1cad345524084a630039a2d2c327cd23.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1cad345524084a630039a2d2c327cd23.json new file mode 100644 index 0000000..9e3cc5f --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1cad345524084a630039a2d2c327cd23.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Secret Key":["Clave secreta"],"Publishable Key":["Clave publicable"],"Please enter a secret key in the same mode as the publishable key.":["Por favor, introduce una clave secreta del mismo modo que la clave publicable."],"Please enter a valid secret key (starting with \"sk_\" or \"rk_\").":["Por favor, introduce una clave secreta v\u00e1lida (que empiece con \u00absk_\u00bb o \u00abrk_\u00bb)."],"Please enter a valid publishable key (starting with \"pk_\").":["Por favor, introduce una clave publicable v\u00e1lida (que empiece con \u00abpk_\u00bb)."],"Your API details can be obtained from your {{link}}PayPal account{{\/link}}":["Los detalles de tu API los puedes obtener en tu {{link}}cuenta de PayPal{{\/link}}"],"Connect your eWAY account":["Conecta tu cuenta de eWAY"],"Customer Password":["Contrase\u00f1a de cliente"],"Customer API Key":["Clave de cliente de la API"],"eWAY connected successfully":["eWAY conectado correctamente"],"Please enter your customer password":["Por favor,\u00a0introduce tu contrase\u00f1a de cliente"],"Please enter your customer API key ":["Por favor, introduce tu clave de cliente de la API"],"Create account":["Crear cuenta"],"eWAY":["eWAY"],"A PayPal account is required to process payments. Connect your store to your PayPal account.":["Para procesar los pagos, es necesaria una cuenta de PayPal. Conecta tu tienda con tu cuenta de PayPal."],"You will be redirected to the PayPal website to create the connection.":["Ser\u00e1s redirigido a la web de PayPal para crear la conexi\u00f3n."],"By clicking \"Set up,\" you agree to the {{link}}Terms of Service{{\/link}}":["Al hacer clic en \u00abConfiguraci\u00f3n\u00bb, est\u00e1 de acuerdo con los {{link}}t\u00e9rminos de servicio{{\/link}}"],"Setting up a store for a client? {{link}}Start here{{\/link}}":["\u00bfConfigurando una tienda para un cliente? {{link}}Empieza aqu\u00ed{{\/link}}"],"Accept credit card payments the easy way! No setup fees. No monthly fees. Just 2.9% + $0.30 per transaction on U.S. issued cards. ":["\u00a1Acepta pagos con tarjeta de cr\u00e9dito de forma f\u00e1cil! Sin cuotas de configuraci\u00f3n. Sin cuotas mensuales. Solo el 2,9 % m\u00e1s 0,30 $ por transacci\u00f3n en tarjetas emitidas en los EE.UU."],"Connect your Klarna account":["Conecta tu cuenta de Klarna"]," Selling CBD products is only supported by Square.":[" La venta de productos de CBD solo est\u00e1 soportada por Square."],"Passphrase":["Frase de contrase\u00f1a"],"Take payments via bank transfer.":["Acepta pagos mediante transferencia bancaria."],"Take payments in cash upon delivery.":["Acepta pagos en efectivo en el momento de la entrega."],"Selecting this extension will configure your store to use South African rands as the selected currency.":["Al seleccionar esta extensi\u00f3n, tu tienda se configurar\u00e1 para usar rands sudafricanos como moneda seleccionada."],"Merchant Key":["Clave de vendedor"],"Merchant ID":["ID de vendedor"],"PayFast connected successfully":["PayFast conectado correctamente."],"Please enter your passphrase":["Por favor, introduce tu contrase\u00f1a"],"Please enter your merchant ID":["Por favor, introduce tu ID de vendedor"],"Connect your PayFast account":["Conecta tu cuenta de PayFast"],"PayFast":["PayFast"],"Connect your PayPal account":["Conecta tu cuenta de PayPal"],"There was an error connecting to WooCommerce Payments. Please try again or connect later in store settings.":["Ha habido un error al conectar con WooCommerce Payments. Por favor, int\u00e9ntalo de nuevo o con\u00e9ctalo m\u00e1s tarde en los ajustes de la tienda."],"WooCommerce Payments connected successfully.":["WooCommerce Payments conectado correctamente."],"Connect your Square account":["Conecta tu cuenta de Square"],"A Square account is required to process payments. You will be redirected to the Square website to create the connection.":["Se necesita una cuenta de Square para procesar los pagos. Ser\u00e1s redirigido a la web de Square para crear la conexi\u00f3n."],"Connect your store to your Stripe account. Don\u2019t have a Stripe account? Create one.":["Conecta tu tienda a tu cuenta de Stripe. \u00bfNo tienes una cuenta de Stripe? Crea una."],"A Stripe account is required to process payments.":["Se necesita una cuenta de Stripe para procesar los pagos."],"Connect your Stripe account":["Conecta tu cuenta de Stripe"],"Your API details can be obtained from your {{docsLink}}Stripe account{{\/docsLink}}. Don\u2019t have a Stripe account? {{registerLink}}Create one.{{\/registerLink}}":["Los detalles de la API pueden obtenerse desde tu {{docsLink}}cuenta de Stripe{{\/docsLink}}. \u00bfNo tienes una cuenta en Stripe? {{registerLink}}Crea una.{{\/registerLink}}"],"Please enter an account number or IBAN":["Por favor, introduce un n\u00famero de cuenta o IBAN"],"WooCommerce Payments":["WooCommerce Payments"],"These details are required to receive payments via bank transfer":["Estos detalles son obligatorios para recibir pagos mediante transferencia bancaria"],"Add your bank details":["A\u00f1ade los detalles de tu banco"],"Direct bank transfer details added successfully":["Detalles para transferencia bancaria directa a\u00f1adidos correctamente"],"There was a problem saving your payment settings":["Ha habido un problema al guardar tus ajustes de pago"],"Securely accept credit and debit cards with one low rate, no surprise fees (custom rates available). Sell online and in store and track sales and inventory in one place.":["Acepta de forma segura tarjetas de cr\u00e9dito y d\u00e9bito con una baja tarifa, sin cuotas sorpresa (disponibles tarifas personalizadas). Vende online y en tienda f\u00edsica y sigue las ventas y el inventario en un solo lugar."],"Accept debit and credit cards in 135+ currencies, methods such as Alipay, and one-touch checkout with Apple Pay.":["Acepta tarjetas de d\u00e9bito y cr\u00e9dito en m\u00e1s de 135 monedas, m\u00e9todos como Alipay y pago con un solo toque con Apple Pay."],"PayPal Checkout":["Pago con PayPal"],"Choose the payment that you want, pay now, pay later or slice it. No credit card numbers, no passwords, no worries.":["Elige el pago que quieras, pagar ahora, pagar m\u00e1s tarde o div\u00eddelo. Sin n\u00fameros de tarjeta, sin contrase\u00f1as, sin preocupaciones."],"Credit cards - powered by Stripe":["Tarjetas de cr\u00e9dito - gestionado por Stripe"],"Stripe connected successfully.":["Stripe conectado correctamente."],"There was an error connecting to Square. Please try again or skip to connect later in store settings.":["Ocurri\u00f3 un error al conectar con Square. Por favor, int\u00e9ntalo de nuevo o s\u00e1ltate este paso para conectarte m\u00e1s tarde en los ajustes de la tienda."],"Square connected successfully.":["Square conectado correctamente."],"Please enter your API password":["Por favor, introduce tu contrase\u00f1a de la API"],"Please enter your API username":["Por favor, introduce tu nombre de usuario de la API"],"There was a problem saving your payment settings.":["Ocurri\u00f3 un problema al guardar tus ajustes de pagos."],"Klarna can be configured under your {{link}}store settings{{\/link}}. Figure out {{helpLink}}what you need{{\/helpLink}}.":["Klarna se puede configurar en tus {{link}}ajustes de la tienda{{\/link}}. Descubre {{helpLink}}qu\u00e9 necesitas{{\/helpLink}}."],"PayPal connected successfully.":["PayPal conectado correctamente."],"Your API details can be obtained from your {{link}}PayFast account{{\/link}}":["Tus detalles de la API los puedes obtener en tu {{link}}cuenta de PayFast{{\/link}}"],"Please enter your merchant key":["Por favor, introduce tu clave de vendedor"],"Your API details can be obtained from your {{link}}eWAY account{{\/link}}":["Los detalles de tu API los puedes obtener en tu {{link}}cuenta de PayPal{{\/link}}"],"Proceed":["Ejecutar"],"The PayFast extension for WooCommerce enables you to accept payments by Credit Card and EFT via one of South Africa\u2019s most popular payment gateways. No setup fees or monthly subscription costs.":["La extensi\u00f3n PayFast para WooCommerce te permite aceptar pagos mediante tarjeta de cr\u00e9dito y EFT gracias a una de las pasarelas de pago m\u00e1s populares de Sud\u00e1frica. No hay cuotas de activaci\u00f3n ni costes de suscripci\u00f3n."],"The eWAY extension for WooCommerce allows you to take credit card payments directly on your store without redirecting your customers to a third party site to make payment.":["La extensi\u00f3n eWAY para WooCommerce te permite recibir pagos directamente por tarjeta de cr\u00e9dito en tu tienda sin redirigir a tus clientes a otro sitio para hacer el pago."],"Square":["Cuadrado"],"Klarna Payments":["Pagos Klarna"],"Klarna Checkout":["Pago con Klarna"],"Please enter a valid email address":["Por favor, introduce una direcci\u00f3n de correo electr\u00f3nico v\u00e1lida"],"Create a PayPal account for me":["Crear una cuenta PayPal para mi"],"Connect":["Conectar"],"Safe and secure payments using credit cards or your customer's PayPal account.":["Pagos seguros y protegidos usando tarjetas de cr\u00e9dito o la cuenta PayPal de tu cliente."],"Email address":["Direcci\u00f3n de correo electr\u00f3nico"],"IBAN":["IBAN"],"BIC \/ Swift":["BIC \/ Swift"],"Bank name":["Nombre del banco"],"Account number":["N\u00famero de cuenta"],"Account name":["Nombre de la cuenta"],"Direct bank transfer":["Transferencia bancaria directa"],"Sort code":["C\u00f3digo de clasificaci\u00f3n"],"API Username":["Nombre de usuario de la API"],"API Password":["Contrase\u00f1a de la API"],"Save":["Guardar"],"Cash on delivery":["Contra reembolso"],"Continue":["Seguir"],"Settings":["Ajustes"]}},"comment":{"reference":"packages\/woocommerce-admin\/dist\/chunks\/9.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1e6e582c38fd3046aa3c225009d2a90c.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1e6e582c38fd3046aa3c225009d2a90c.json new file mode 100644 index 0000000..2746f9d --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1e6e582c38fd3046aa3c225009d2a90c.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Product on sale":["Producto en oferta"],"Sale":["Oferta"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/atomic\/blocks\/product-elements\/sale-badge\/block.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1ea5d0886ad91cfcb79dbb02979efdc3.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1ea5d0886ad91cfcb79dbb02979efdc3.json new file mode 100644 index 0000000..337154a --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1ea5d0886ad91cfcb79dbb02979efdc3.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"No posts yet":["Todav\u00eda no hay entradas"],"Oops, our posts aren't loading right now":["Vaya, nuestras entradas no se est\u00e1n cargando justo ahora"],"Read {{link}}the WooCommerce blog{{\/link}} for more tips on marketing your store":["Lee el {{link}}blog de WooCommerce{{\/link}} para m\u00e1s trucos sobre c\u00f3mo hacer marketing en tu tienda"],"Recommended coupon extensions":["Extensiones de cup\u00f3n recomendadas"],"Take your coupon marketing to the next level with our recommended coupon extensions.":["Lleva tu marketing de cupones al siguiente nivel con nuestras extensiones de cupones recomendadas."],"Learn the ins and outs of successful coupon marketing from the experts at WooCommerce.":["Aprende los entresijos del marketing exitoso de cupones de los expertos de WooCommerce."],"The extension has been successfully activated.":["La extensi\u00f3n se ha activado correctamente."],"WooCommerce knowledge base":["Base de conocimientos de WooCommerce"],"There was an error loading recommended extensions.":["Ha habido un error al cargar las extensiones recomendadas."],"There was an error loading installed extensions.":["Ha habido un error al cargar las extensiones instaladas."],"There was an error trying to activate the extension.":["Ha habido un error al intentar activar la extensi\u00f3n."],"Learn the ins and outs of successful marketing from the experts at WooCommerce.":["Aprende los entresijos de un marketing de \u00e9xito de los expertos de WooCommerce."],"Great marketing requires the right tools. Take your marketing to the next level with our recommended marketing extensions.":["Un gran marketing necesita las herramientas adecuadas. Lleva tu marketing al siguiente nivel con nuestras extensiones de marketing recomendadas."],"Recommended extensions":["Extensiones recomendadas"],"Comma":["Coma"],"Backtick":["Acento grave"],"Mutable settings should be mutated via data store.":["Los ajustes modificables deben modificarse a trav\u00e9s del almacenamiento de datos."],"Mutable settings should be accessed via data store.":["Los ajustes modificables deber\u00edan ser accesibles a trav\u00e9s del almacenamiento de datos."],"Period":["Per\u00edodo"]}},"comment":{"reference":"packages\/woocommerce-admin\/dist\/wp-admin-scripts\/marketing-coupons.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1fce6066a1f86a34fccc35420cf1071e.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1fce6066a1f86a34fccc35420cf1071e.json new file mode 100644 index 0000000..030a39f --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1fce6066a1f86a34fccc35420cf1071e.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Sorry, an error occurred":["Lo siento, ha ocurrido un error"],"Retry":["Volver a intentar"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/editor-components\/error-placeholder\/index.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1fd108afcd6b1150ccd257c03371fcf4.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1fd108afcd6b1150ccd257c03371fcf4.json new file mode 100644 index 0000000..8af560b --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1fd108afcd6b1150ccd257c03371fcf4.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Display a grid of products currently on sale.":["Muestra una cuadr\u00edcula de productos actualmente rebajados."],"On Sale Products":["Productos en oferta"],"WooCommerce":["WooCommerce"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/blocks\/product-on-sale\/index.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1ff2b9879bf907d438b0a402676a8c76.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1ff2b9879bf907d438b0a402676a8c76.json new file mode 100644 index 0000000..84cd4f3 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-1ff2b9879bf907d438b0a402676a8c76.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Log in.":["Acceder."],"Already have an account? ":["\u00bfYa tienes una cuenta? "]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/blocks\/cart-checkout\/checkout\/form\/login-prompt.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-202a71ed52f50963a82272da6ac2c610.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-202a71ed52f50963a82272da6ac2c610.json new file mode 100644 index 0000000..c61dd15 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-202a71ed52f50963a82272da6ac2c610.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"categories\u0004Excludes":["Excluye"],"categories\u0004Includes":["Incluye"],"Select categories":["Seleccionar categor\u00edas"],"{{title}}Category{{\/title}} {{rule \/}} {{filter \/}}":["{{title}}Categor\u00eda{{\/title}} {{rule \/}} {{filter \/}}"],"Remove categories filter":["Eliminar el filtro de categor\u00edas"],"A sentence describing filters for Variations. See screen shot for context: https:\/\/cloudup.com\/cSsUY9VeCVJ\u0004Variations Match {{select \/}} Filters":["Variaciones que coinciden con los filtros {{select \/}}"],"Select a category filter match":["Selecciona una coincidencia de filtro de categor\u00eda"],"product attribute\u0004Is Not":["No es"],"product attribute\u0004Is":["Es"],"Select attributes":["Seleccionar atributos"],"Select a product attribute filter match":["Selecciona una coincidencia de filtro de atributo de producto"],"Remove attribute filter":["Quitar el filtro de atributos"],"Search attributes":["Buscar atributos"],"Type to search for a variation":["Escribe para buscar una variaci\u00f3n"],"Single Variation":["Variaci\u00f3n simple"],"Check at least two variations below to compare":["Selecciona a menos dos variaciones de las siguientes para compararlas"],"Indication of a low quantity\u0004Low":["Baja"],"Search by variation name or SKU":["Buscar por nombre de variaci\u00f3n o SKU"],"variation sold":["variaci\u00f3n vendida","variaciones vendidas"],"%d variations":["%d variaciones"],"All Variations":["Todas las variaciones"],"Compare Variations":["Comparar variaciones"],"Search for variations to compare":["Busca variaciones para compararlas"],"net sales":["ventas netas"],"products\u0004Excludes":["Excluido"],"products\u0004Includes":["Incluido"],"Select products":["Seleccionar productos"],"Remove products filter":["Quitar filtro de productos"],"{{title}}Product{{\/title}} {{rule \/}} {{filter \/}}":["{{title}}Producto{{\/title}} {{rule \/}} {{filter \/}}"],"Select a product filter match":["Elige una coincidencia de filtro de producto"],"Advanced Filters":["Filtros avanzados"],"item sold":["art\u00edculo vendido","art\u00edculos vendidos"],"Comparison":["Comparaci\u00f3n"],"Previous Year:":["A\u00f1o anterior:"],"No data for the selected date range":["No hay datos en el rango de fechas solicitado"],"No data for the current search":["No hay datos para la b\u00fasqueda actual"],"{{title}}Attribute{{\/title}} {{rule \/}} {{filter \/}}":["{{title}}Atributo{{\/title}} {{rule \/}} {{filter \/}}"],"Product \/ Variation Title":["Producto \/ T\u00edtulo de la variaci\u00f3n"],"Net Sales":["Ventas netas"],"Items Sold":["Art\u00edculos vendidos"],"Compare":["Comparar"],"Previous Period:":["Periodo anterior:"],"TAX":["IMPUESTO"],"Search categories":["Buscar categor\u00edas"],"Attribute":["Atributo"],"Search products":["Buscar productos"],"Show":["Mostrar"],"orders":["pedidos","pedidos"],"Products":["Productos"],"Variations":["Variaciones"],"SKU":["SKU"],"Categories":["Categor\u00edas"],"Status":["Estado"],"Orders":["Pedidos"],"Stock":["Inventario"]}},"comment":{"reference":"packages\/woocommerce-admin\/dist\/chunks\/analytics-report-variations.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-206459d169f12b652a1dabe78a376826.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-206459d169f12b652a1dabe78a376826.json new file mode 100644 index 0000000..b48e61c --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-206459d169f12b652a1dabe78a376826.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Display a grid of products from your selected categories.":["Muestra una cuadr\u00edcula de productos de las categor\u00edas que elijas"],"Products by Category":["Productos por categor\u00eda"],"WooCommerce":["WooCommerce"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/blocks\/product-category\/index.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-20e7fc3ea96346f2d1f05ca5e7847392.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-20e7fc3ea96346f2d1f05ca5e7847392.json new file mode 100644 index 0000000..6b45c3a --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-20e7fc3ea96346f2d1f05ca5e7847392.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"The last inner block will follow other content.":["El \u00faltimo bloque interior seguir\u00e1 al resto del contenido."],"The last inner block will be aligned vertically.":["El \u00faltimo bloque interior se alinear\u00e1 verticalmente"],"Align Last Block":["Alinear \u00faltimo bloque"],"Rows":["Filas"],"Columns":["Columnas"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/editor-components\/grid-layout-control\/index.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-21fee52f2b4be704278bd81018c89b15.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-21fee52f2b4be704278bd81018c89b15.json new file mode 100644 index 0000000..a67c28c --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-21fee52f2b4be704278bd81018c89b15.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"\u2026":["\u2026"],"Navigate to another page":["Navegar a otra p\u00e1gina"],"Next page":["P\u00e1gina siguiente"],"Previous page":["P\u00e1gina anterior"],"Page %d":["P\u00e1gina %d"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/base\/components\/pagination\/index.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-23a5d7b5185c7352a40e30649d5daad8.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-23a5d7b5185c7352a40e30649d5daad8.json new file mode 100644 index 0000000..8f98125 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-23a5d7b5185c7352a40e30649d5daad8.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Creative Mail for WooCommerce":["Creative Mail para WooCommerce"],"WooCommerce Shipping & Tax":["WooCommerce Shipping & Tax"],"Google Ads":["Google Ads"],"WooCommerce PayPal":["WooCommerce PayPal"],"WooCommerce Payments":["WooCommerce Payments"],"WooCommerce PayFast":["WooCommerce PayFast"],"WooCommerce Stripe":["WooCommerce Stripe"],"WooCommerce ShipStation Gateway":["WooCommerce ShipStation Gateway"],"There was a problem updating your settings.":["Ha habido un problema al actualizar tus ajustes."],"MM\/DD\/YYYY":["DD\/MM\/YYYY"],"Facebook for WooCommerce":["Facebook for WooCommerce"],"Mailchimp for WooCommerce":["Mailchimp for WooCommerce"],"Klarna Payments for WooCommerce":["Klarna Payments for WooCommerce"],"Klarna Checkout for WooCommerce":["Klarna Checkout for WooCommerce"],"Jetpack":["Jetpack"]}},"comment":{"reference":"packages\/woocommerce-admin\/dist\/data\/index.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-25681209877dbbf4b351e01720af480c.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-25681209877dbbf4b351e01720af480c.json new file mode 100644 index 0000000..592836c --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-25681209877dbbf4b351e01720af480c.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Orange":["Naranja"],"Lightweight baseball cap":["Gorra de beisbol ligera"],"Cap":["Gorra"],"Yellow":["Amarillo"],"Warm hat for winter":["Sombrero caliente de invierno"],"Beanie":["Gorro"],"Color":["Color"],"Small":["Peque\u00f1o"],"Size":["Tama\u00f1o"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/previews\/cart.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-266b21f550f6c336217746f77332e8d9.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-266b21f550f6c336217746f77332e8d9.json new file mode 100644 index 0000000..65d4e83 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-266b21f550f6c336217746f77332e8d9.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Category images are hidden.":["Las im\u00e1genes de las categor\u00edas est\u00e1n ocultas."],"Category images are visible.":["Las im\u00e1genes de las categor\u00edas son visibles."],"Show category images":["Mostrar im\u00e1genes de categor\u00edas"],"Display style":["Estilo de visualizaci\u00f3n"],"List Settings":["Ajustes de la lista"],"Empty categories are hidden.":["Las categor\u00edas vac\u00edas est\u00e1n ocultas."],"Empty categories are visible.":["Las categor\u00edas vac\u00edas son visibles."],"Show empty categories":["Mostrar categor\u00edas vac\u00edas"],"Hierarchy is hidden.":["La jerarqu\u00eda est\u00e1 oculta."],"Hierarchy is visible.":["La jerarqu\u00eda es visible."],"Product count is hidden.":["La cantidad de productos est\u00e1 oculta."],"Product count is visible.":["La cantidad de productos es visible."],"Show product count":["Mostrar cantidad de productos"],"Product Categories List":["Lista de categor\u00edas de productos"],"This block shows product categories for your store. To use it, you'll first need to create a product and assign it to a category.":["Este bloque muestra las categor\u00edas de productos de tu tienda. Para usarlo primero tienes que crear un producto y asignarlo a una categor\u00eda."],"List":["Lista"],"Dropdown":["Lista desplegable"],"Show hierarchy":["Mostrar jerarqu\u00eda"],"Content":["Contenido"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/blocks\/product-categories\/block.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-272ce40a99e1a33c3ee6c9cbce70cc33.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-272ce40a99e1a33c3ee6c9cbce70cc33.json new file mode 100644 index 0000000..0aac111 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-272ce40a99e1a33c3ee6c9cbce70cc33.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Product Stock Indicator":["Indicador del inventario del producto"],"Display product stock status.":["Mostrar el estado del inventario del producto."]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/atomic\/blocks\/product-elements\/stock-indicator\/constants.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2744127682072dcdf2583cd6dc64ce99.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2744127682072dcdf2583cd6dc64ce99.json new file mode 100644 index 0000000..a0940f6 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2744127682072dcdf2583cd6dc64ce99.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Display a list of categories belonging to a product.":["Muestra una lista de categor\u00edas pertenecientes a un producto."],"Product Category List":["Lista de categor\u00edas del producto"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/atomic\/blocks\/product-elements\/category-list\/constants.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-275818e8b4218da8c54856bdf290d8f6.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-275818e8b4218da8c54856bdf290d8f6.json new file mode 100644 index 0000000..963b2ff --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-275818e8b4218da8c54856bdf290d8f6.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Comma":["Coma"],"Backtick":["Acento grave"],"%s stock could not be updated.":["El inventario de %s no se pudo actualizar."],"%s stock updated.":["Inventario de %s actualizado."],"No products with low stock":["No hay productos con pocas existencias."],"There was an error getting your low stock products. Please try again.":["Hubo un error al recuperar tus productos con pocas existencias. Por favor, int\u00e9ntalo de nuevo."],"You currently have no products running low on stock.":["Actualmente no tienes ning\u00fan producto con pocas existencias."],"Your stock is in good shape.":["Tus existencias est\u00e1n en buena forma."],"Update stock":["Actualizar inventario"],"%d in stock":["Hay %d existencias"],"in stock":["con existencias"],"Reload":["Recargar"],"Save":["Guardar"],"Period":["Per\u00edodo"],"Cancel":["Cancelar"],"Stock":["Inventario"]}},"comment":{"reference":"packages\/woocommerce-admin\/dist\/chunks\/activity-panels-stock.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-27c3c96efb4bdb0e7c38db93c5b151be.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-27c3c96efb4bdb0e7c38db93c5b151be.json new file mode 100644 index 0000000..257818a --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-27c3c96efb4bdb0e7c38db93c5b151be.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Tags:":["Etiquetas:"]}},"comment":{"reference":"packages\/woocommerce-blocks\/build\/atomic-block-components\/tag-list-frontend.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-28373221fc2f980b198a22af0e736c42.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-28373221fc2f980b198a22af0e736c42.json new file mode 100644 index 0000000..1e78fac --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-28373221fc2f980b198a22af0e736c42.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Product on sale":["Producto en oferta"],"Sale":["Oferta"]}},"comment":{"reference":"packages\/woocommerce-blocks\/build\/atomic-block-components\/sale-badge-frontend.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-287f246e61a201cec5ac1e37a10190bc.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-287f246e61a201cec5ac1e37a10190bc.json new file mode 100644 index 0000000..e952a9b --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-287f246e61a201cec5ac1e37a10190bc.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Display a checkout form so your customers can submit orders.":["Muestra un formulario de pago para que tus clientes puedan hacer pedidos."],"Checkout":["Finalizar compra"],"WooCommerce":["WooCommerce"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/blocks\/cart-checkout\/checkout\/index.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2a130218c40b2b37eedb3857f22c90a1.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2a130218c40b2b37eedb3857f22c90a1.json new file mode 100644 index 0000000..f438ca5 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2a130218c40b2b37eedb3857f22c90a1.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"g:ia":["G:i"],"F j, Y":["j F, Y"],"{{attribute \/}} {{equals \/}} {{value \/}}":["{{attribute \/}} {{equals \/}} {{value \/}}"],"Abort":["Abortar"],"Press the down arrow key to interact with the calendar and select a date.":["Pulsa la tecla de flecha abajo para interactuar con el calendario y seleccionar una fecha."],"Comma":["Coma"],"Backtick":["Acento grave"],"Add an image":["A\u00f1ade una imagen"],"Select or upload image":["Selecciona o sube una imagen"],"Continue without installing":["Continuar sin instalar"],"Install & enable":["Instalar y activar"],"No data to display":["No hay datos para mostrar"],"Attribute value":["Valor del atributo."],"Retry":["Volver a intentar"],"+%d more":["+%d m\u00e1s"],"Columns:":["Columnas:"],"Sort by %s in descending order":["Ordenar por %s en orden descendente"],"Sort by %s in ascending order":["Ordenar por %s en orden ascendente"],"(scroll to see more)":["(scroll para ver m\u00e1s)"],"Previous Period:":["Periodo anterior:"],"%d%%":["%d%%"],"No change from %s":["Ning\u00fan cambio desde %s"],"Down %d%% from %s":["Abajo %d%% desde %s"],"Up %d%% from %s":["Arriba %d%% desde %s"],"Performance Indicators":["Indicadores de rendimiento"],"Search results updated.":["Resultados de b\u00fasqueda actualizados."],"%d item selected":["%d art\u00edculo seleccionado","%d art\u00edculos seleccionados"],"Search for items":["Buscar art\u00edculos"],"Results":["Resultados"],"Filters":["Filtros"],"%1$s out of %2$s stars.":["%1$s de %2$s estrellas."],"Go to page":["Ir a la p\u00e1gina"],"Next Page":["P\u00e1gina siguiente"],"Previous Page":["P\u00e1gina anterior"],"Page %d of %d":["P\u00e1gina %d de %d"],"Date Range":["Rango de fechas"],"select a date range":["selecciona un rango de fechas"],"Start Date":["Fecha de inicio"],"%s is not selectable.":["%s no se puede seleccionar."],"Go to the first or last day of a week.":["Ir al primer o \u00faltimo d\u00eda de una semana."],"Switch months.":["Cambiar de mes."],"Question mark":["Signo de interrogaci\u00f3n"],"Clear Dates":["Vaciar fechas"],"Clear Date":["Vaciar fecha"],"Interact with the calendar and select start and end dates.":["Interact\u00faa con el calendario y selecciona las fechas de inicio y fin."],"Calendar":["Calendario"],"compare to":["comparar con"],"Total %d":["Total %d"],"Bar chart":["Gr\u00e1fico de barras"],"Line chart":["Gr\u00e1fico de l\u00edneas"],"By year":["Por a\u00f1o"],"By quarter":["Por trimestre"],"By month":["Por mes"],"By week":["Por semana"],"By day":["Por d\u00eda"],"By hour":["Por hora"],"Clear all filters":["Vaciar todos los filtros"],"Add a Filter":["A\u00f1ade un filtro"],"select a date":["selecciona una fecha"],"Choose a date":["Elige una fecha"],"%(field)s range end":["%(field)s fin del rango"],"%(field)s range start":["%(field)s inicio del rango"],"minimum value input\u0004%(field)s minimum amount":["%(field)s cantidad m\u00ednima"],"maximum value input\u0004%(field)s maximum amount":["%(field)s cantidad m\u00e1xima"],"Numerical range inputs arranged on a single line\u0004{{rangeStart \/}}{{span}} and {{\/span}}{{rangeEnd \/}}":["{{rangeStart \/}}{{span}} y {{\/span}}{{rangeEnd \/}}"],"Clear all":["Vaciar todo"],"%1$s (%2$s of %3$s)":["%1$s (%2$s de %3$s)"],"Remove %s":["Quitar %s"],"TAX":["IMPUESTO"],"Return to the date input field.":["Volver al campo de introducci\u00f3n de fecha."],"Date range inputs arranged on a single line\u0004{{after \/}}{{span}} and {{\/span}}{{before \/}}":["{{after \/}}{{span}} y {{\/span}}{{before \/}}"],"Choose which values to display":["Elije qu\u00e9 valores mostrar"],"List of data points available for filtering. Use arrow keys to cycle through the list. Click a data point for a detailed report.":["Lista de puntos de datos disponibles para el filtrado. Utiliza las teclas de flecha para desplazarte por la lista. Haz clic en un punto de datos para obtener un informe detallado."],"Move backward for selected items":["Retrocede a los art\u00edculos seleccionados"],"All taxes with codes that include {{query \/}}":["Todos los impuestos con c\u00f3digos que incluyan {{query \/}}"],"All products with titles that include {{query \/}}":["Todos los productos con t\u00edtulos que incluyan {{query \/}}"],"All customers with names that include {{query \/}}":["Todos los clientes con nombres que incluyan {{query \/}}"],"All coupons with codes that include {{query \/}}":["Todos los cupones con c\u00f3digos que incluyan {{query \/}}"],"All categories with titles that include {{query \/}}":["Todas las categor\u00edas con t\u00edtulos que incluyan {{query \/}}"],"No results.":["Ning\u00fan resultado."],"%d result found, use up and down arrow keys to navigate.":["%d resultado encontrado, usa las teclas de flecha arriba y abajo para navegar.","%d resultados encontrados, usa las teclas de flecha arriba y abajo para navegar."],"No results for %s":["No hay resultados para %s"],"No items found.":["No se encontraron art\u00edculos."],"Clear all selected items":["Vaciar todos los art\u00edculos seleccionados"],"filter report to show:":["filtro del informe a mostrar:"],"select a preset period":["selecciona un periodo de preajuste"],"vs.":["frente al"],"Presets":["Preajustes"],"Select date range and comparison":["Selecciona un rango de fechas a comparar"],"Choose to apply any or all filters":["Elige si aplicar alguno o todos los filtros"],"MM\/DD\/YYYY":["DD\/MM\/YYYY"],"MMM D, YYYY":["D MMM, YYYY"],"Your requested data is loading":["Los datos que has solicitado se est\u00e1n cargando"],"You may select up to %d items.":["Puedes seleccionar hasta %d art\u00edculos."],"Selected. %s":["Seleccionada. %s"],"Select %s as an end date.":["Seleccionar %s como fecha de fin."],"Select %s as a start date.":["Seleccionar %s como fecha de inicio."],"Move backward (up) and forward (down) by one week.":["Mu\u00e9vete atr\u00e1s (arriba) y adelante (abajo) de semana en semana."],"Move backward (left) and forward (right) by one day.":["Mu\u00e9vete atr\u00e1s (izquierda) y adelante (derecha) de d\u00eda en d\u00eda."],"Select the date in focus.":["Selecciona la fecha en cuesti\u00f3n."],"Escape key":["Tecla Escape"],"Home and end keys":["Teclas Inicio y Fin"],"page up and page down keys":["teclas de p\u00e1gina arriba y p\u00e1gina abajo"],"up and down arrow keys":["teclas de flechas arriba y abajo"],"Right and left arrow keys":["Teclas de flechas izquierda y derecha"],"Enter key":["Tecla Intro"],"Move forward to switch to the next month.":["Mover hacia delante para cambiar al mes siguiente."],"Move backward to switch to the previous month.":["Mover hacia atr\u00e1s para cambiar al mes anterior."],"Date input describing a selected date range's end date in format %s":["Anotaci\u00f3n de fecha que describe la fecha final de un rango de fechas seleccionado en formato %s"],"End Date":["Fecha de fin"],"Date input describing a selected date range's start date in format %s":["Anotaci\u00f3n de fecha que describe la fecha de inicio de un rango de fechas seleccionado en formato %s"],"Date input describing a selected date in format %s":["Anotaci\u00f3n de fecha que describe una fecha seleccionada en formato %s"],"Rows per page":["Filas por p\u00e1gina"],"Attribute name":["Nombre del atributo"],"Select":["Seleccionar"],"Filter":["Filtrar"],"to":["hasta"],"Custom":["Personalizado"],"Notifications":["Avisos"],"Close":["Cerrar"],"Period":["Per\u00edodo"],"Reset":["Restablecer"],"Any":["Cualquiera"],"All":["Todos"],"Remove image":["Quitar imagen"],"N\/A":["N\/D"],"No thanks":["No, gracias"],"Continue":["Seguir"],"Update":["Actualizar"]}},"comment":{"reference":"packages\/woocommerce-admin\/dist\/components\/index.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2a131eb5bf930c716935378d6cbb25d2.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2a131eb5bf930c716935378d6cbb25d2.json new file mode 100644 index 0000000..2f66ff4 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2a131eb5bf930c716935378d6cbb25d2.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Direct bank transfer":["Transferencia bancaria directa"]}},"comment":{"reference":"packages\/woocommerce-blocks\/build\/wc-payment-method-bacs.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2a4f5667ed4e81d44f6ccfb84523b904.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2a4f5667ed4e81d44f6ccfb84523b904.json new file mode 100644 index 0000000..8387751 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2a4f5667ed4e81d44f6ccfb84523b904.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"This block lists reviews for a selected product. %s doesn't have any reviews yet, but they will show up here when it does.":["Este bloque lista las valoraciones de un producto seleccionado. %s todav\u00eda no tiene valoraciones, pero se mostrar\u00e1n aqu\u00ed cuando las tenga."],"Reviews by Product":["Valoraciones por producto"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/blocks\/reviews\/reviews-by-product\/no-reviews-placeholder.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2a7eca80ba12897c21ffaa74974c8fef.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2a7eca80ba12897c21ffaa74974c8fef.json new file mode 100644 index 0000000..f569b67 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2a7eca80ba12897c21ffaa74974c8fef.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"All Reviews":["Todas las valoraciones"],"Show a list of all product reviews.":["Muestra una lista de todas las valoraciones de productos."],"WooCommerce":["WooCommerce"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/blocks\/reviews\/all-reviews\/index.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2af5e068de293517b1bb2cfc58cf9989.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2af5e068de293517b1bb2cfc58cf9989.json new file mode 100644 index 0000000..a9a8827 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2af5e068de293517b1bb2cfc58cf9989.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Tags:":["Etiquetas:"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/atomic\/blocks\/product-elements\/tag-list\/block.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2cd54bc9eeab906cf0f6abb2399e9fb7.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2cd54bc9eeab906cf0f6abb2399e9fb7.json new file mode 100644 index 0000000..2345fc3 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2cd54bc9eeab906cf0f6abb2399e9fb7.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Mutable settings should be mutated via data store.":["Los ajustes modificables deben modificarse a trav\u00e9s del almacenamiento de datos."],"Mutable settings should be accessed via data store.":["Los ajustes modificables deber\u00edan ser accesibles a trav\u00e9s del almacenamiento de datos."],"Continue setup.":["Continuar con la configuraci\u00f3n."],"You've added your first tax rate!":["\u00a1Has a\u00f1adido tu primera tasa de impuestos!"]}},"comment":{"reference":"packages\/woocommerce-admin\/dist\/wp-admin-scripts\/onboarding-tax-notice.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2d000e7ced69fed51ef7de882445014e.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2d000e7ced69fed51ef7de882445014e.json new file mode 100644 index 0000000..f573e08 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2d000e7ced69fed51ef7de882445014e.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"SKU:":["SKU:"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/atomic\/blocks\/product-elements\/sku\/block.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2e2892cb61344eb4fdac4c1e37619262.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2e2892cb61344eb4fdac4c1e37619262.json new file mode 100644 index 0000000..c52765a --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2e2892cb61344eb4fdac4c1e37619262.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Check at least two categories below to compare":["Selecciona al menos dos categor\u00edas de las siguientes para compararlas"],"Search by category name":["Buscar por nombre de categor\u00eda"],"category":["categor\u00eda","categor\u00edas"],"%d categories":["%d categor\u00edas"],"%d products":["%d productos"],"Compare Categories":["Comparar categor\u00edas"],"Search for categories to compare":["Busca categor\u00edas para compararlas"],"Single Category":["Categor\u00eda \u00fanica"],"Type to search for a category":["Teclea para buscar una categor\u00eda"],"All Categories":["Todas las categor\u00edas"],"net sales":["ventas netas"],"order":["pedido","pedidos"],"item sold":["art\u00edculo vendido","art\u00edculos vendidos"],"Comparison":["Comparaci\u00f3n"],"Net Sales":["Ventas netas"],"Items Sold":["Art\u00edculos vendidos"],"Compare":["Comparar"],"Category":["Categor\u00eda"],"Show":["Mostrar"],"Products":["Productos"],"Categories":["Categor\u00edas"],"Orders":["Pedidos"]}},"comment":{"reference":"packages\/woocommerce-admin\/dist\/chunks\/analytics-report-categories.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2e5b773a600e6595bad14136c2d73f08.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2e5b773a600e6595bad14136c2d73f08.json new file mode 100644 index 0000000..06271bd --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2e5b773a600e6595bad14136c2d73f08.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Show the currently active product filters. Works in combination with the All Products and filters blocks.":["Muestra el filtro de productos actualmente activos. Funciona en combinaci\u00f3n con los bloques de todos los productos y de filtrado."],"Active Product Filters":["Filtros de productos activos"],"Active filters":["Filtros activos"],"WooCommerce":["WooCommerce"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/blocks\/active-filters\/index.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2e8ff1f945781cdab678c7cf64caff6f.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2e8ff1f945781cdab678c7cf64caff6f.json new file mode 100644 index 0000000..f161650 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2e8ff1f945781cdab678c7cf64caff6f.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"SKU:":["SKU:"]}},"comment":{"reference":"packages\/woocommerce-blocks\/build\/atomic-block-components\/sku.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2ea015f5a250d849138bc331f2668c60.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2ea015f5a250d849138bc331f2668c60.json new file mode 100644 index 0000000..a48c244 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2ea015f5a250d849138bc331f2668c60.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Product on sale":["Producto en oferta"],"Sale":["Oferta"]}},"comment":{"reference":"packages\/woocommerce-blocks\/build\/atomic-block-components\/image-frontend.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2ff2080d2d38b66bf6e2d5e3d2c64bb5.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2ff2080d2d38b66bf6e2d5e3d2c64bb5.json new file mode 100644 index 0000000..893a93a --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-2ff2080d2d38b66bf6e2d5e3d2c64bb5.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Shopping cart.":["Carrito de compras."],"Cart":["Carrito"],"WooCommerce":["WooCommerce"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/blocks\/cart-checkout\/cart\/index.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-3239989f0cbcc3489b2cf8c18d04dc05.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-3239989f0cbcc3489b2cf8c18d04dc05.json new file mode 100644 index 0000000..dd1749d --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-3239989f0cbcc3489b2cf8c18d04dc05.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"%1$s (%2$d unit)":["%1$s (%2$d unidad)","%1$s (%2$d unidades)"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/base\/components\/cart-checkout\/shipping-rates-control\/package.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-324138858b6bcb278c27e314613e684c.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-324138858b6bcb278c27e314613e684c.json new file mode 100644 index 0000000..2a60199 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-324138858b6bcb278c27e314613e684c.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Edit your cart":["Edita tu carrito"],"Please edit your cart and try again.":["Por favor, modifica tu carrito e int\u00e9ntalo de nuevo."],"There is a problem with your cart":["Ha habido un problema con tu carrito"],"Checkout error":["Error al finalizar compra"],"There was a problem checking out. Please try again. If the problem persists, please get in touch with us so we can assist.":["Ha ocurrido un problema durante el registro. Por favor, int\u00e9ntalo de nuevo. Si persiste el problema, por favor, ponte en contacto con nosotros para que podamos ayudarte."],"Retry":["Volver a intentar"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/blocks\/cart-checkout\/checkout\/checkout-order-error\/index.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-3305d9de59961a847c212b100798fb50.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-3305d9de59961a847c212b100798fb50.json new file mode 100644 index 0000000..e59bc3d --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-3305d9de59961a847c212b100798fb50.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Discounted price:":["Precio con descuento:"],"Previous price:":["Precio anterior:"]}},"comment":{"reference":"packages\/woocommerce-blocks\/build\/atomic-block-components\/price-frontend.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-34b7393e5b07373be089898508bfd837.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-34b7393e5b07373be089898508bfd837.json new file mode 100644 index 0000000..ee675af --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-34b7393e5b07373be089898508bfd837.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Payment Methods":["M\u00e9todos de pago"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/base\/components\/payment-methods\/payment-method-options.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-354416042f4f6ddf578099737d7be093.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-354416042f4f6ddf578099737d7be093.json new file mode 100644 index 0000000..ee06742 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-354416042f4f6ddf578099737d7be093.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Please select a value.":["Por favor, selecciona un valor."]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/base\/components\/select\/validated.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-36e7818bfdfd4a6943db89e1565c4cc7.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-36e7818bfdfd4a6943db89e1565c4cc7.json new file mode 100644 index 0000000..eca6af1 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-36e7818bfdfd4a6943db89e1565c4cc7.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"A search box to allow customers to search for products by keyword.":["Una caja de b\u00fasqueda para permitir a los clientes buscar productos mediante el teclado."],"Search products\u2026":["Buscar productos..."],"Product Search":["B\u00fasqueda de productos"],"Search":["Buscar"],"WooCommerce":["WooCommerce"]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/blocks\/product-search\/index.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-376011c6441a11bdb03699ed8ce0becc.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-376011c6441a11bdb03699ed8ce0becc.json new file mode 100644 index 0000000..1f07627 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-376011c6441a11bdb03699ed8ce0becc.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Between %1$s and %2$s":["Entre %1$s y %2$s"],"Remove \"%s\"":["Eliminar \u00ab%s\u00bb"],"Clear All Filters":["Vaciar todos los filtros"],"Remove %s filter":["Eliminar el filtro %s"],"Clear All":["Vaciar todo"],"Blue":["Azul"],"Color":["Color"],"Small":["Peque\u00f1o"],"Size":["Tama\u00f1o"],"Up to %s":["Hasta %s"],"From %s":["Desde %s"],"Oops!":["\u00a1Vaya!"],"There was an error loading the content.":["Ha habido un error al cargar este contenido."],"Error:":["Error:"],"and":["y"],"Price":["Precio"],"Remove":["Eliminar"]}},"comment":{"reference":"packages\/woocommerce-blocks\/build\/active-filters-frontend.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-38946f5d8b83961eb0af530272a1d081.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-38946f5d8b83961eb0af530272a1d081.json new file mode 100644 index 0000000..509472f --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-38946f5d8b83961eb0af530272a1d081.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"Choose a product to display its categories.":["Elige un producto para mostrar sus categor\u00edas."]}},"comment":{"reference":"packages\/woocommerce-blocks\/assets\/js\/atomic\/blocks\/product-elements\/category-list\/edit.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-38b8e72fdda975a53bd48996f0a154e3.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-38b8e72fdda975a53bd48996f0a154e3.json new file mode 100644 index 0000000..a8ca277 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-38b8e72fdda975a53bd48996f0a154e3.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"%d left in stock":["Quedan %d disponibles"],"In Stock":["Con existencias"],"Out of Stock":["Sin existencias"],"Available on backorder":["Disponible para reserva"]}},"comment":{"reference":"packages\/woocommerce-blocks\/build\/atomic-block-components\/stock-indicator-frontend.js"}} \ No newline at end of file diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-3925e1feb7b90b12ac3114967c21e6f9.json b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-3925e1feb7b90b12ac3114967c21e6f9.json new file mode 100644 index 0000000..c5ae475 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/languages/plugins/woocommerce-es_ES-3925e1feb7b90b12ac3114967c21e6f9.json @@ -0,0 +1 @@ +{"translation-revision-date":"2020-12-08 17:56:20+0000","generator":"GlotPress\/3.0.0-alpha.2","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","plural-forms":"nplurals=2; plural=n != 1;","lang":"es"},"There was an error registering the payment method with id '%s': ":["Ocurri\u00f3 un error al registrar el m\u00e9todo de pago con el id '%s':"],"%1$s (%2$d unit)":["%1$s (%2$d unidad)","%1$s (%2$d unidades)"],"Remove \"%s\"":["Eliminar \u00ab%s\u00bb"],"Shipping to %s":["Enviar a %s"],"The cart has encountered an unexpected error.
' + ); + form.$form.find( '.wc-no-matching-variations' ).slideDown( 200 ); + } + } + }, + complete: function() { + form.$form.unblock(); + } + } ); + } else { + form.$form.trigger( 'update_variation_values' ); + + var matching_variations = form.findMatchingVariations( form.variationData, currentAttributes ), + variation = matching_variations.shift(); + + if ( variation ) { + form.$form.trigger( 'found_variation', [ variation ] ); + } else { + form.$form.trigger( 'reset_data' ); + attributes.chosenCount = 0; + + if ( ! form.loading ) { + form.$form + .find( '.single_variation' ) + .after( + '' + + wc_add_to_cart_variation_params.i18n_no_matching_variations_text + + '
' + ); + form.$form.find( '.wc-no-matching-variations' ).slideDown( 200 ); + } + } + } + } else { + form.$form.trigger( 'update_variation_values' ); + form.$form.trigger( 'reset_data' ); + } + + // Show reset link. + form.toggleResetLink( attributes.chosenCount > 0 ); + }; + + /** + * Triggered when a variation has been found which matches all attributes. + */ + VariationForm.prototype.onFoundVariation = function( event, variation ) { + var form = event.data.variationForm, + $sku = form.$product.find( '.product_meta' ).find( '.sku' ), + $weight = form.$product.find( + '.product_weight, .woocommerce-product-attributes-item--weight .woocommerce-product-attributes-item__value' + ), + $dimensions = form.$product.find( + '.product_dimensions, .woocommerce-product-attributes-item--dimensions .woocommerce-product-attributes-item__value' + ), + $qty = form.$singleVariationWrap.find( '.quantity' ), + purchasable = true, + variation_id = '', + template = false, + $template_html = ''; + + if ( variation.sku ) { + $sku.wc_set_content( variation.sku ); + } else { + $sku.wc_reset_content(); + } + + if ( variation.weight ) { + $weight.wc_set_content( variation.weight_html ); + } else { + $weight.wc_reset_content(); + } + + if ( variation.dimensions ) { + // Decode HTML entities. + $dimensions.wc_set_content( $.parseHTML( variation.dimensions_html )[0].data ); + } else { + $dimensions.wc_reset_content(); + } + + form.$form.wc_variations_image_update( variation ); + + if ( ! variation.variation_is_visible ) { + template = wp_template( 'unavailable-variation-template' ); + } else { + template = wp_template( 'variation-template' ); + variation_id = variation.variation_id; + } + + $template_html = template( { + variation: variation + } ); + $template_html = $template_html.replace( '/**/', '' ); + + form.$singleVariation.html( $template_html ); + form.$form.find( 'input[name="variation_id"], input.variation_id' ).val( variation.variation_id ).change(); + + // Hide or show qty input + if ( variation.is_sold_individually === 'yes' ) { + $qty.find( 'input.qty' ).val( '1' ).attr( 'min', '1' ).attr( 'max', '' ).change(); + $qty.hide(); + } else { + + var $qty_input = $qty.find( 'input.qty' ), + qty_val = parseFloat( $qty_input.val() ); + + if ( isNaN( qty_val ) ) { + qty_val = variation.min_qty; + } else { + qty_val = qty_val > parseFloat( variation.max_qty ) ? variation.max_qty : qty_val; + qty_val = qty_val < parseFloat( variation.min_qty ) ? variation.min_qty : qty_val; + } + + $qty_input.attr( 'min', variation.min_qty ).attr( 'max', variation.max_qty ).val( qty_val ).change(); + $qty.show(); + } + + // Enable or disable the add to cart button + if ( ! variation.is_purchasable || ! variation.is_in_stock || ! variation.variation_is_visible ) { + purchasable = false; + } + + // Reveal + if ( $.trim( form.$singleVariation.text() ) ) { + form.$singleVariation.slideDown( 200 ).trigger( 'show_variation', [ variation, purchasable ] ); + } else { + form.$singleVariation.show().trigger( 'show_variation', [ variation, purchasable ] ); + } + }; + + /** + * Triggered when an attribute field changes. + */ + VariationForm.prototype.onChange = function( event ) { + var form = event.data.variationForm; + + form.$form.find( 'input[name="variation_id"], input.variation_id' ).val( '' ).change(); + form.$form.find( '.wc-no-matching-variations' ).remove(); + + if ( form.useAjax ) { + form.$form.trigger( 'check_variations' ); + } else { + form.$form.trigger( 'woocommerce_variation_select_change' ); + form.$form.trigger( 'check_variations' ); + } + + // Custom event for when variation selection has been changed + form.$form.trigger( 'woocommerce_variation_has_changed' ); + }; + + /** + * Escape quotes in a string. + * @param {string} string + * @return {string} + */ + VariationForm.prototype.addSlashes = function( string ) { + string = string.replace( /'/g, '\\\'' ); + string = string.replace( /"/g, '\\\"' ); + return string; + }; + + /** + * Updates attributes in the DOM to show valid values. + */ + VariationForm.prototype.onUpdateAttributes = function( event ) { + var form = event.data.variationForm, + attributes = form.getChosenAttributes(), + currentAttributes = attributes.data; + + if ( form.useAjax ) { + return; + } + + // Loop through selects and disable/enable options based on selections. + form.$attributeFields.each( function( index, el ) { + var current_attr_select = $( el ), + current_attr_name = current_attr_select.data( 'attribute_name' ) || current_attr_select.attr( 'name' ), + show_option_none = $( el ).data( 'show_option_none' ), + option_gt_filter = ':gt(0)', + attached_options_count = 0, + new_attr_select = $( '' ), + selected_attr_val = current_attr_select.val() || '', + selected_attr_val_valid = true; + + // Reference options set at first. + if ( ! current_attr_select.data( 'attribute_html' ) ) { + var refSelect = current_attr_select.clone(); + + refSelect.find( 'option' ).removeAttr( 'disabled attached' ).removeAttr( 'selected' ); + + // Legacy data attribute. + current_attr_select.data( + 'attribute_options', + refSelect.find( 'option' + option_gt_filter ).get() + ); + current_attr_select.data( 'attribute_html', refSelect.html() ); + } + + new_attr_select.html( current_attr_select.data( 'attribute_html' ) ); + + // The attribute of this select field should not be taken into account when calculating its matching variations: + // The constraints of this attribute are shaped by the values of the other attributes. + var checkAttributes = $.extend( true, {}, currentAttributes ); + + checkAttributes[ current_attr_name ] = ''; + + var variations = form.findMatchingVariations( form.variationData, checkAttributes ); + + // Loop through variations. + for ( var num in variations ) { + if ( typeof( variations[ num ] ) !== 'undefined' ) { + var variationAttributes = variations[ num ].attributes; + + for ( var attr_name in variationAttributes ) { + if ( variationAttributes.hasOwnProperty( attr_name ) ) { + var attr_val = variationAttributes[ attr_name ], + variation_active = ''; + + if ( attr_name === current_attr_name ) { + if ( variations[ num ].variation_is_active ) { + variation_active = 'enabled'; + } + + if ( attr_val ) { + // Decode entities. + attr_val = $( '' ).html( attr_val ).text(); + + // Attach to matching options by value. This is done to compare + // TEXT values rather than any HTML entities. + var $option_elements = new_attr_select.find( 'option' ); + if ( $option_elements.length ) { + for (var i = 0, len = $option_elements.length; i < len; i++) { + var $option_element = $( $option_elements[i] ), + option_value = $option_element.val(); + + if ( attr_val === option_value ) { + $option_element.addClass( 'attached ' + variation_active ); + break; + } + } + } + } else { + // Attach all apart from placeholder. + new_attr_select.find( 'option:gt(0)' ).addClass( 'attached ' + variation_active ); + } + } + } + } + } + } + + // Count available options. + attached_options_count = new_attr_select.find( 'option.attached' ).length; + + // Check if current selection is in attached options. + if ( selected_attr_val ) { + selected_attr_val_valid = false; + + if ( 0 !== attached_options_count ) { + new_attr_select.find( 'option.attached.enabled' ).each( function() { + var option_value = $( this ).val(); + + if ( selected_attr_val === option_value ) { + selected_attr_val_valid = true; + return false; // break. + } + }); + } + } + + // Detach the placeholder if: + // - Valid options exist. + // - The current selection is non-empty. + // - The current selection is valid. + // - Placeholders are not set to be permanently visible. + if ( attached_options_count > 0 && selected_attr_val && selected_attr_val_valid && ( 'no' === show_option_none ) ) { + new_attr_select.find( 'option:first' ).remove(); + option_gt_filter = ''; + } + + // Detach unattached. + new_attr_select.find( 'option' + option_gt_filter + ':not(.attached)' ).remove(); + + // Finally, copy to DOM and set value. + current_attr_select.html( new_attr_select.html() ); + current_attr_select.find( 'option' + option_gt_filter + ':not(.enabled)' ).prop( 'disabled', true ); + + // Choose selected value. + if ( selected_attr_val ) { + // If the previously selected value is no longer available, fall back to the placeholder (it's going to be there). + if ( selected_attr_val_valid ) { + current_attr_select.val( selected_attr_val ); + } else { + current_attr_select.val( '' ).change(); + } + } else { + current_attr_select.val( '' ); // No change event to prevent infinite loop. + } + }); + + // Custom event for when variations have been updated. + form.$form.trigger( 'woocommerce_update_variation_values' ); + }; + + /** + * Get chosen attributes from form. + * @return array + */ + VariationForm.prototype.getChosenAttributes = function() { + var data = {}; + var count = 0; + var chosen = 0; + + this.$attributeFields.each( function() { + var attribute_name = $( this ).data( 'attribute_name' ) || $( this ).attr( 'name' ); + var value = $( this ).val() || ''; + + if ( value.length > 0 ) { + chosen ++; + } + + count ++; + data[ attribute_name ] = value; + }); + + return { + 'count' : count, + 'chosenCount': chosen, + 'data' : data + }; + }; + + /** + * Find matching variations for attributes. + */ + VariationForm.prototype.findMatchingVariations = function( variations, attributes ) { + var matching = []; + for ( var i = 0; i < variations.length; i++ ) { + var variation = variations[i]; + + if ( this.isMatch( variation.attributes, attributes ) ) { + matching.push( variation ); + } + } + return matching; + }; + + /** + * See if attributes match. + * @return {Boolean} + */ + VariationForm.prototype.isMatch = function( variation_attributes, attributes ) { + var match = true; + for ( var attr_name in variation_attributes ) { + if ( variation_attributes.hasOwnProperty( attr_name ) ) { + var val1 = variation_attributes[ attr_name ]; + var val2 = attributes[ attr_name ]; + if ( val1 !== undefined && val2 !== undefined && val1.length !== 0 && val2.length !== 0 && val1 !== val2 ) { + match = false; + } + } + } + return match; + }; + + /** + * Show or hide the reset link. + */ + VariationForm.prototype.toggleResetLink = function( on ) { + if ( on ) { + if ( this.$resetVariations.css( 'visibility' ) === 'hidden' ) { + this.$resetVariations.css( 'visibility', 'visible' ).hide().fadeIn(); + } + } else { + this.$resetVariations.css( 'visibility', 'hidden' ); + } + }; + + /** + * Function to call wc_variation_form on jquery selector. + */ + $.fn.wc_variation_form = function() { + new VariationForm( this ); + return this; + }; + + /** + * Stores the default text for an element so it can be reset later + */ + $.fn.wc_set_content = function( content ) { + if ( undefined === this.attr( 'data-o_content' ) ) { + this.attr( 'data-o_content', this.text() ); + } + this.text( content ); + }; + + /** + * Stores the default text for an element so it can be reset later + */ + $.fn.wc_reset_content = function() { + if ( undefined !== this.attr( 'data-o_content' ) ) { + this.text( this.attr( 'data-o_content' ) ); + } + }; + + /** + * Stores a default attribute for an element so it can be reset later + */ + $.fn.wc_set_variation_attr = function( attr, value ) { + if ( undefined === this.attr( 'data-o_' + attr ) ) { + this.attr( 'data-o_' + attr, ( ! this.attr( attr ) ) ? '' : this.attr( attr ) ); + } + if ( false === value ) { + this.removeAttr( attr ); + } else { + this.attr( attr, value ); + } + }; + + /** + * Reset a default attribute for an element so it can be reset later + */ + $.fn.wc_reset_variation_attr = function( attr ) { + if ( undefined !== this.attr( 'data-o_' + attr ) ) { + this.attr( attr, this.attr( 'data-o_' + attr ) ); + } + }; + + /** + * Reset the slide position if the variation has a different image than the current one + */ + $.fn.wc_maybe_trigger_slide_position_reset = function( variation ) { + var $form = $( this ), + $product = $form.closest( '.product' ), + $product_gallery = $product.find( '.images' ), + reset_slide_position = false, + new_image_id = ( variation && variation.image_id ) ? variation.image_id : ''; + + if ( $form.attr( 'current-image' ) !== new_image_id ) { + reset_slide_position = true; + } + + $form.attr( 'current-image', new_image_id ); + + if ( reset_slide_position ) { + $product_gallery.trigger( 'woocommerce_gallery_reset_slide_position' ); + } + }; + + /** + * Sets product images for the chosen variation + */ + $.fn.wc_variations_image_update = function( variation ) { + var $form = this, + $product = $form.closest( '.product' ), + $product_gallery = $product.find( '.images' ), + $gallery_nav = $product.find( '.flex-control-nav' ), + $gallery_img = $gallery_nav.find( 'li:eq(0) img' ), + $product_img_wrap = $product_gallery + .find( '.woocommerce-product-gallery__image, .woocommerce-product-gallery__image--placeholder' ) + .eq( 0 ), + $product_img = $product_img_wrap.find( '.wp-post-image' ), + $product_link = $product_img_wrap.find( 'a' ).eq( 0 ); + + if ( variation && variation.image && variation.image.src && variation.image.src.length > 1 ) { + // See if the gallery has an image with the same original src as the image we want to switch to. + var galleryHasImage = $gallery_nav.find( 'li img[data-o_src="' + variation.image.gallery_thumbnail_src + '"]' ).length > 0; + + // If the gallery has the image, reset the images. We'll scroll to the correct one. + if ( galleryHasImage ) { + $form.wc_variations_image_reset(); + } + + // See if gallery has a matching image we can slide to. + var slideToImage = $gallery_nav.find( 'li img[src="' + variation.image.gallery_thumbnail_src + '"]' ); + + if ( slideToImage.length > 0 ) { + slideToImage.trigger( 'click' ); + $form.attr( 'current-image', variation.image_id ); + window.setTimeout( function() { + $( window ).trigger( 'resize' ); + $product_gallery.trigger( 'woocommerce_gallery_init_zoom' ); + }, 20 ); + return; + } + + $product_img.wc_set_variation_attr( 'src', variation.image.src ); + $product_img.wc_set_variation_attr( 'height', variation.image.src_h ); + $product_img.wc_set_variation_attr( 'width', variation.image.src_w ); + $product_img.wc_set_variation_attr( 'srcset', variation.image.srcset ); + $product_img.wc_set_variation_attr( 'sizes', variation.image.sizes ); + $product_img.wc_set_variation_attr( 'title', variation.image.title ); + $product_img.wc_set_variation_attr( 'data-caption', variation.image.caption ); + $product_img.wc_set_variation_attr( 'alt', variation.image.alt ); + $product_img.wc_set_variation_attr( 'data-src', variation.image.full_src ); + $product_img.wc_set_variation_attr( 'data-large_image', variation.image.full_src ); + $product_img.wc_set_variation_attr( 'data-large_image_width', variation.image.full_src_w ); + $product_img.wc_set_variation_attr( 'data-large_image_height', variation.image.full_src_h ); + $product_img_wrap.wc_set_variation_attr( 'data-thumb', variation.image.src ); + $gallery_img.wc_set_variation_attr( 'src', variation.image.gallery_thumbnail_src ); + $product_link.wc_set_variation_attr( 'href', variation.image.full_src ); + } else { + $form.wc_variations_image_reset(); + } + + window.setTimeout( function() { + $( window ).trigger( 'resize' ); + $form.wc_maybe_trigger_slide_position_reset( variation ); + $product_gallery.trigger( 'woocommerce_gallery_init_zoom' ); + }, 20 ); + }; + + /** + * Reset main image to defaults. + */ + $.fn.wc_variations_image_reset = function() { + var $form = this, + $product = $form.closest( '.product' ), + $product_gallery = $product.find( '.images' ), + $gallery_nav = $product.find( '.flex-control-nav' ), + $gallery_img = $gallery_nav.find( 'li:eq(0) img' ), + $product_img_wrap = $product_gallery + .find( '.woocommerce-product-gallery__image, .woocommerce-product-gallery__image--placeholder' ) + .eq( 0 ), + $product_img = $product_img_wrap.find( '.wp-post-image' ), + $product_link = $product_img_wrap.find( 'a' ).eq( 0 ); + + $product_img.wc_reset_variation_attr( 'src' ); + $product_img.wc_reset_variation_attr( 'width' ); + $product_img.wc_reset_variation_attr( 'height' ); + $product_img.wc_reset_variation_attr( 'srcset' ); + $product_img.wc_reset_variation_attr( 'sizes' ); + $product_img.wc_reset_variation_attr( 'title' ); + $product_img.wc_reset_variation_attr( 'data-caption' ); + $product_img.wc_reset_variation_attr( 'alt' ); + $product_img.wc_reset_variation_attr( 'data-src' ); + $product_img.wc_reset_variation_attr( 'data-large_image' ); + $product_img.wc_reset_variation_attr( 'data-large_image_width' ); + $product_img.wc_reset_variation_attr( 'data-large_image_height' ); + $product_img_wrap.wc_reset_variation_attr( 'data-thumb' ); + $gallery_img.wc_reset_variation_attr( 'src' ); + $product_link.wc_reset_variation_attr( 'href' ); + }; + + $(function() { + if ( typeof wc_add_to_cart_variation_params !== 'undefined' ) { + $( '.variations_form' ).each( function() { + $( this ).wc_variation_form(); + }); + } + }); + + /** + * Matches inline variation objects to chosen attributes + * @deprecated 2.6.9 + * @type {Object} + */ + var wc_variation_form_matcher = { + find_matching_variations: function( product_variations, settings ) { + var matching = []; + for ( var i = 0; i < product_variations.length; i++ ) { + var variation = product_variations[i]; + + if ( wc_variation_form_matcher.variations_match( variation.attributes, settings ) ) { + matching.push( variation ); + } + } + return matching; + }, + variations_match: function( attrs1, attrs2 ) { + var match = true; + for ( var attr_name in attrs1 ) { + if ( attrs1.hasOwnProperty( attr_name ) ) { + var val1 = attrs1[ attr_name ]; + var val2 = attrs2[ attr_name ]; + if ( val1 !== undefined && val2 !== undefined && val1.length !== 0 && val2.length !== 0 && val1 !== val2 ) { + match = false; + } + } + } + return match; + } + }; + + /** + * Avoids using wp.template where possible in order to be CSP compliant. + * wp.template uses internally eval(). + * @param {string} templateId + * @return {Function} + */ + var wp_template = function( templateId ) { + var html = document.getElementById( 'tmpl-' + templateId ).textContent; + var hard = false; + // any <# #> interpolate (evaluate). + hard = hard || /<#\s?data\./.test( html ); + // any data that is NOT data.variation. + hard = hard || /{{{?\s?data\.(?!variation\.).+}}}?/.test( html ); + // any data access deeper than 1 level e.g. + // data.variation.object.item + // data.variation.object['item'] + // data.variation.array[0] + hard = hard || /{{{?\s?data\.variation\.[\w-]*[^\s}]/.test ( html ); + if ( hard ) { + return wp.template( templateId ); + } + return function template ( data ) { + var variation = data.variation || {}; + return html.replace( /({{{?)\s?data\.variation\.([\w-]*)\s?(}}}?)/g, function( _, open, key, close ) { + // Error in the format, ignore. + if ( open.length !== close.length ) { + return ''; + } + var replacement = variation[ key ] || ''; + // {{{ }}} => interpolate (unescaped). + // {{ }} => interpolate (escaped). + // https://codex.wordpress.org/Javascript_Reference/wp.template + if ( open.length === 2 ) { + return window.escape( replacement ); + } + return replacement; + }); + }; + }; + +})( jQuery, window, document ); diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/assets/js/frontend/add-to-cart-variation.min.js b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/assets/js/frontend/add-to-cart-variation.min.js new file mode 100644 index 0000000..601bf54 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/assets/js/frontend/add-to-cart-variation.min.js @@ -0,0 +1 @@ +!function(y,c,i,n){var t=function(t){var a=this;a.$form=t,a.$attributeFields=t.find(".variations select"),a.$singleVariation=t.find(".single_variation"),a.$singleVariationWrap=t.find(".single_variation_wrap"),a.$resetVariations=t.find(".reset_variations"),a.$product=t.closest(".product"),a.variationData=t.data("product_variations"),a.useAjax=!1===a.variationData,a.xhr=!1,a.loading=!0,a.$singleVariationWrap.show(),a.$form.off(".wc-variation-form"),a.getChosenAttributes=a.getChosenAttributes.bind(a),a.findMatchingVariations=a.findMatchingVariations.bind(a),a.isMatch=a.isMatch.bind(a),a.toggleResetLink=a.toggleResetLink.bind(a),t.on("click.wc-variation-form",".reset_variations",{variationForm:a},a.onReset),t.on("reload_product_variations",{variationForm:a},a.onReload),t.on("hide_variation",{variationForm:a},a.onHide),t.on("show_variation",{variationForm:a},a.onShow),t.on("click",".single_add_to_cart_button",{variationForm:a},a.onAddToCart),t.on("reset_data",{variationForm:a},a.onResetDisplayedVariation),t.on("reset_image",{variationForm:a},a.onResetImage),t.on("change.wc-variation-form",".variations select",{variationForm:a},a.onChange),t.on("found_variation.wc-variation-form",{variationForm:a},a.onFoundVariation),t.on("check_variations.wc-variation-form",{variationForm:a},a.onFindVariation),t.on("update_variation_values.wc-variation-form",{variationForm:a},a.onUpdateAttributes),setTimeout(function(){t.trigger("check_variations"),t.trigger("wc_variation_form",a),a.loading=!1},100)};t.prototype.onReset=function(t){t.preventDefault(),t.data.variationForm.$attributeFields.val("").change(),t.data.variationForm.$form.trigger("reset_data")},t.prototype.onReload=function(t){t=t.data.variationForm;t.variationData=t.$form.data("product_variations"),t.useAjax=!1===t.variationData,t.$form.trigger("check_variations")},t.prototype.onHide=function(t){t.preventDefault(),t.data.variationForm.$form.find(".single_add_to_cart_button").removeClass("wc-variation-is-unavailable").addClass("disabled wc-variation-selection-needed"),t.data.variationForm.$form.find(".woocommerce-variation-add-to-cart").removeClass("woocommerce-variation-add-to-cart-enabled").addClass("woocommerce-variation-add-to-cart-disabled")},t.prototype.onShow=function(t,a,i){t.preventDefault(),i?(t.data.variationForm.$form.find(".single_add_to_cart_button").removeClass("disabled wc-variation-selection-needed wc-variation-is-unavailable"),t.data.variationForm.$form.find(".woocommerce-variation-add-to-cart").removeClass("woocommerce-variation-add-to-cart-disabled").addClass("woocommerce-variation-add-to-cart-enabled")):(t.data.variationForm.$form.find(".single_add_to_cart_button").removeClass("wc-variation-selection-needed").addClass("disabled wc-variation-is-unavailable"),t.data.variationForm.$form.find(".woocommerce-variation-add-to-cart").removeClass("woocommerce-variation-add-to-cart-enabled").addClass("woocommerce-variation-add-to-cart-disabled")),wp.mediaelement&&t.data.variationForm.$form.find(".wp-audio-shortcode, .wp-video-shortcode").not(".mejs-container").filter(function(){return!y(this).parent().hasClass("mejs-mediaelement")}).mediaelementplayer(wp.mediaelement.settings)},t.prototype.onAddToCart=function(t){y(this).is(".disabled")&&(t.preventDefault(),y(this).is(".wc-variation-is-unavailable")?c.alert(wc_add_to_cart_variation_params.i18n_unavailable_text):y(this).is(".wc-variation-selection-needed")&&c.alert(wc_add_to_cart_variation_params.i18n_make_a_selection_text))},t.prototype.onResetDisplayedVariation=function(t){t=t.data.variationForm;t.$product.find(".product_meta").find(".sku").wc_reset_content(),t.$product.find(".product_weight, .woocommerce-product-attributes-item--weight .woocommerce-product-attributes-item__value").wc_reset_content(),t.$product.find(".product_dimensions, .woocommerce-product-attributes-item--dimensions .woocommerce-product-attributes-item__value").wc_reset_content(),t.$form.trigger("reset_image"),t.$singleVariation.slideUp(200).trigger("hide_variation")},t.prototype.onResetImage=function(t){t.data.variationForm.$form.wc_variations_image_update(!1)},t.prototype.onFindVariation=function(t,a){var i=t.data.variationForm,e=void 0!==a?a:i.getChosenAttributes(),a=e.data;e.count&&e.count===e.chosenCount?i.useAjax?(i.xhr&&i.xhr.abort(),i.$form.block({message:null,overlayCSS:{background:"#fff",opacity:.6}}),a.product_id=parseInt(i.$form.data("product_id"),10),a.custom_data=i.$form.data("custom_data"),i.xhr=y.ajax({url:wc_add_to_cart_variation_params.wc_ajax_url.toString().replace("%%endpoint%%","get_variation"),type:"POST",data:a,success:function(t){t?i.$form.trigger("found_variation",[t]):(i.$form.trigger("reset_data"),e.chosenCount=0,i.loading||(i.$form.find(".single_variation").after(''+wc_add_to_cart_variation_params.i18n_no_matching_variations_text+"
"),i.$form.find(".wc-no-matching-variations").slideDown(200)))},complete:function(){i.$form.unblock()}})):(i.$form.trigger("update_variation_values"),(a=i.findMatchingVariations(i.variationData,a).shift())?i.$form.trigger("found_variation",[a]):(i.$form.trigger("reset_data"),e.chosenCount=0,i.loading||(i.$form.find(".single_variation").after(''+wc_add_to_cart_variation_params.i18n_no_matching_variations_text+"
"),i.$form.find(".wc-no-matching-variations").slideDown(200)))):(i.$form.trigger("update_variation_values"),i.$form.trigger("reset_data")),i.toggleResetLink(0 0 ) {
+ requestManager.run();
+ }
+ };
+
+ $.ajax( this.requests[0] );
+ };
+
+ /**
+ * Handle the add to cart event.
+ */
+ AddToCartHandler.prototype.onAddToCart = function( e ) {
+ var $thisbutton = $( this );
+
+ if ( $thisbutton.is( '.ajax_add_to_cart' ) ) {
+ if ( ! $thisbutton.attr( 'data-product_id' ) ) {
+ return true;
+ }
+
+ e.preventDefault();
+
+ $thisbutton.removeClass( 'added' );
+ $thisbutton.addClass( 'loading' );
+
+ // Allow 3rd parties to validate and quit early.
+ if ( false === $( document.body ).triggerHandler( 'should_send_ajax_request.adding_to_cart', [ $thisbutton ] ) ) {
+ $( document.body ).trigger( 'ajax_request_not_sent.adding_to_cart', [ false, false, $thisbutton ] );
+ return true;
+ }
+
+ var data = {};
+
+ // Fetch changes that are directly added by calling $thisbutton.data( key, value )
+ $.each( $thisbutton.data(), function( key, value ) {
+ data[ key ] = value;
+ });
+
+ // Fetch data attributes in $thisbutton. Give preference to data-attributes because they can be directly modified by javascript
+ // while `.data` are jquery specific memory stores.
+ $.each( $thisbutton[0].dataset, function( key, value ) {
+ data[ key ] = value;
+ });
+
+ // Trigger event.
+ $( document.body ).trigger( 'adding_to_cart', [ $thisbutton, data ] );
+
+ e.data.addToCartHandler.addRequest({
+ type: 'POST',
+ url: wc_add_to_cart_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'add_to_cart' ),
+ data: data,
+ success: function( response ) {
+ if ( ! response ) {
+ return;
+ }
+
+ if ( response.error && response.product_url ) {
+ window.location = response.product_url;
+ return;
+ }
+
+ // Redirect to cart option
+ if ( wc_add_to_cart_params.cart_redirect_after_add === 'yes' ) {
+ window.location = wc_add_to_cart_params.cart_url;
+ return;
+ }
+
+ // Trigger event so themes can refresh other areas.
+ $( document.body ).trigger( 'added_to_cart', [ response.fragments, response.cart_hash, $thisbutton ] );
+ },
+ dataType: 'json'
+ });
+ }
+ };
+
+ /**
+ * Update fragments after remove from cart event in mini-cart.
+ */
+ AddToCartHandler.prototype.onRemoveFromCart = function( e ) {
+ var $thisbutton = $( this ),
+ $row = $thisbutton.closest( '.woocommerce-mini-cart-item' );
+
+ e.preventDefault();
+
+ $row.block({
+ message: null,
+ overlayCSS: {
+ opacity: 0.6
+ }
+ });
+
+ e.data.addToCartHandler.addRequest({
+ type: 'POST',
+ url: wc_add_to_cart_params.wc_ajax_url.toString().replace( '%%endpoint%%', 'remove_from_cart' ),
+ data: {
+ cart_item_key : $thisbutton.data( 'cart_item_key' )
+ },
+ success: function( response ) {
+ if ( ! response || ! response.fragments ) {
+ window.location = $thisbutton.attr( 'href' );
+ return;
+ }
+
+ $( document.body ).trigger( 'removed_from_cart', [ response.fragments, response.cart_hash, $thisbutton ] );
+ },
+ error: function() {
+ window.location = $thisbutton.attr( 'href' );
+ return;
+ },
+ dataType: 'json'
+ });
+ };
+
+ /**
+ * Update cart page elements after add to cart events.
+ */
+ AddToCartHandler.prototype.updateButton = function( e, fragments, cart_hash, $button ) {
+ $button = typeof $button === 'undefined' ? false : $button;
+
+ if ( $button ) {
+ $button.removeClass( 'loading' );
+
+ if ( fragments ) {
+ $button.addClass( 'added' );
+ }
+
+ // View cart text.
+ if ( fragments && ! wc_add_to_cart_params.is_cart && $button.parent().find( '.added_to_cart' ).length === 0 ) {
+ $button.after( '' + wc_add_to_cart_params.i18n_view_cart + '' );
+ }
+
+ $( document.body ).trigger( 'wc_cart_button_updated', [ $button ] );
+ }
+ };
+
+ /**
+ * Update fragments after add to cart events.
+ */
+ AddToCartHandler.prototype.updateFragments = function( e, fragments ) {
+ if ( fragments ) {
+ $.each( fragments, function( key ) {
+ $( key )
+ .addClass( 'updating' )
+ .fadeTo( '400', '0.6' )
+ .block({
+ message: null,
+ overlayCSS: {
+ opacity: 0.6
+ }
+ });
+ });
+
+ $.each( fragments, function( key, value ) {
+ $( key ).replaceWith( value );
+ $( key ).stop( true ).css( 'opacity', '1' ).unblock();
+ });
+
+ $( document.body ).trigger( 'wc_fragments_loaded' );
+ }
+ };
+
+ /**
+ * Init AddToCartHandler.
+ */
+ new AddToCartHandler();
+});
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/assets/js/frontend/add-to-cart.min.js b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/assets/js/frontend/add-to-cart.min.js
new file mode 100644
index 0000000..21fbaa3
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/assets/js/frontend/add-to-cart.min.js
@@ -0,0 +1 @@
+jQuery(function(d){if("undefined"==typeof wc_add_to_cart_params)return!1;var t=function(){this.requests=[],this.addRequest=this.addRequest.bind(this),this.run=this.run.bind(this),d(document.body).on("click",".add_to_cart_button",{addToCartHandler:this},this.onAddToCart).on("click",".remove_from_cart_button",{addToCartHandler:this},this.onRemoveFromCart).on("added_to_cart",this.updateButton).on("ajax_request_not_sent.adding_to_cart",this.updateButton).on("added_to_cart removed_from_cart",{addToCartHandler:this},this.updateFragments)};t.prototype.addRequest=function(t){this.requests.push(t),1===this.requests.length&&this.run()},t.prototype.run=function(){var t=this,a=t.requests[0].complete;t.requests[0].complete=function(){"function"==typeof a&&a(),t.requests.shift(),0 \
+ \
+ 1\
+ 2\
+ 3\
+ 4\
+ 5\
+ \
+
instead of in the
. Default 'false'. + */ + private static function register_script( $handle, $path, $deps = array( 'jquery' ), $version = WC_VERSION, $in_footer = true ) { + self::$scripts[] = $handle; + wp_register_script( $handle, $path, $deps, $version, $in_footer ); + } + + /** + * Register and enqueue a script for use. + * + * @uses wp_enqueue_script() + * @param string $handle Name of the script. Should be unique. + * @param string $path Full URL of the script, or path of the script relative to the WordPress root directory. + * @param string[] $deps An array of registered script handles this script depends on. + * @param string $version String specifying script version number, if it has one, which is added to the URL as a query string for cache busting purposes. If version is set to false, a version number is automatically added equal to current installed WordPress version. If set to null, no version is added. + * @param boolean $in_footer Whether to enqueue the script before instead of in the
. Default 'false'.
+ */
+ private static function enqueue_script( $handle, $path = '', $deps = array( 'jquery' ), $version = WC_VERSION, $in_footer = true ) {
+ if ( ! in_array( $handle, self::$scripts, true ) && $path ) {
+ self::register_script( $handle, $path, $deps, $version, $in_footer );
+ }
+ wp_enqueue_script( $handle );
+ }
+
+ /**
+ * Register a style for use.
+ *
+ * @uses wp_register_style()
+ * @param string $handle Name of the stylesheet. Should be unique.
+ * @param string $path Full URL of the stylesheet, or path of the stylesheet relative to the WordPress root directory.
+ * @param string[] $deps An array of registered stylesheet handles this stylesheet depends on.
+ * @param string $version String specifying stylesheet version number, if it has one, which is added to the URL as a query string for cache busting purposes. If version is set to false, a version number is automatically added equal to current installed WordPress version. If set to null, no version is added.
+ * @param string $media The media for which this stylesheet has been defined. Accepts media types like 'all', 'print' and 'screen', or media queries like '(orientation: portrait)' and '(max-width: 640px)'.
+ * @param boolean $has_rtl If has RTL version to load too.
+ */
+ private static function register_style( $handle, $path, $deps = array(), $version = WC_VERSION, $media = 'all', $has_rtl = false ) {
+ self::$styles[] = $handle;
+ wp_register_style( $handle, $path, $deps, $version, $media );
+
+ if ( $has_rtl ) {
+ wp_style_add_data( $handle, 'rtl', 'replace' );
+ }
+ }
+
+ /**
+ * Register and enqueue a styles for use.
+ *
+ * @uses wp_enqueue_style()
+ * @param string $handle Name of the stylesheet. Should be unique.
+ * @param string $path Full URL of the stylesheet, or path of the stylesheet relative to the WordPress root directory.
+ * @param string[] $deps An array of registered stylesheet handles this stylesheet depends on.
+ * @param string $version String specifying stylesheet version number, if it has one, which is added to the URL as a query string for cache busting purposes. If version is set to false, a version number is automatically added equal to current installed WordPress version. If set to null, no version is added.
+ * @param string $media The media for which this stylesheet has been defined. Accepts media types like 'all', 'print' and 'screen', or media queries like '(orientation: portrait)' and '(max-width: 640px)'.
+ * @param boolean $has_rtl If has RTL version to load too.
+ */
+ private static function enqueue_style( $handle, $path = '', $deps = array(), $version = WC_VERSION, $media = 'all', $has_rtl = false ) {
+ if ( ! in_array( $handle, self::$styles, true ) && $path ) {
+ self::register_style( $handle, $path, $deps, $version, $media, $has_rtl );
+ }
+ wp_enqueue_style( $handle );
+ }
+
+ /**
+ * Register all WC scripts.
+ */
+ private static function register_scripts() {
+ $suffix = Constants::is_true( 'SCRIPT_DEBUG' ) ? '' : '.min';
+ $version = Constants::get_constant( 'WC_VERSION' );
+
+ $register_scripts = array(
+ 'flexslider' => array(
+ 'src' => self::get_asset_url( 'assets/js/flexslider/jquery.flexslider' . $suffix . '.js' ),
+ 'deps' => array( 'jquery' ),
+ 'version' => '2.7.2',
+ ),
+ 'js-cookie' => array(
+ 'src' => self::get_asset_url( 'assets/js/js-cookie/js.cookie' . $suffix . '.js' ),
+ 'deps' => array(),
+ 'version' => '2.1.4',
+ ),
+ 'jquery-blockui' => array(
+ 'src' => self::get_asset_url( 'assets/js/jquery-blockui/jquery.blockUI' . $suffix . '.js' ),
+ 'deps' => array( 'jquery' ),
+ 'version' => '2.70',
+ ),
+ 'jquery-cookie' => array( // deprecated.
+ 'src' => self::get_asset_url( 'assets/js/jquery-cookie/jquery.cookie' . $suffix . '.js' ),
+ 'deps' => array( 'jquery' ),
+ 'version' => '1.4.1',
+ ),
+ 'jquery-payment' => array(
+ 'src' => self::get_asset_url( 'assets/js/jquery-payment/jquery.payment' . $suffix . '.js' ),
+ 'deps' => array( 'jquery' ),
+ 'version' => '3.0.0',
+ ),
+ 'photoswipe' => array(
+ 'src' => self::get_asset_url( 'assets/js/photoswipe/photoswipe' . $suffix . '.js' ),
+ 'deps' => array(),
+ 'version' => '4.1.1',
+ ),
+ 'photoswipe-ui-default' => array(
+ 'src' => self::get_asset_url( 'assets/js/photoswipe/photoswipe-ui-default' . $suffix . '.js' ),
+ 'deps' => array( 'photoswipe' ),
+ 'version' => '4.1.1',
+ ),
+ 'prettyPhoto' => array( // deprecated.
+ 'src' => self::get_asset_url( 'assets/js/prettyPhoto/jquery.prettyPhoto' . $suffix . '.js' ),
+ 'deps' => array( 'jquery' ),
+ 'version' => '3.1.6',
+ ),
+ 'prettyPhoto-init' => array( // deprecated.
+ 'src' => self::get_asset_url( 'assets/js/prettyPhoto/jquery.prettyPhoto.init' . $suffix . '.js' ),
+ 'deps' => array( 'jquery', 'prettyPhoto' ),
+ 'version' => $version,
+ ),
+ 'select2' => array(
+ 'src' => self::get_asset_url( 'assets/js/select2/select2.full' . $suffix . '.js' ),
+ 'deps' => array( 'jquery' ),
+ 'version' => '4.0.3',
+ ),
+ 'selectWoo' => array(
+ 'src' => self::get_asset_url( 'assets/js/selectWoo/selectWoo.full' . $suffix . '.js' ),
+ 'deps' => array( 'jquery' ),
+ 'version' => '1.0.6',
+ ),
+ 'wc-address-i18n' => array(
+ 'src' => self::get_asset_url( 'assets/js/frontend/address-i18n' . $suffix . '.js' ),
+ 'deps' => array( 'jquery', 'wc-country-select' ),
+ 'version' => $version,
+ ),
+ 'wc-add-payment-method' => array(
+ 'src' => self::get_asset_url( 'assets/js/frontend/add-payment-method' . $suffix . '.js' ),
+ 'deps' => array( 'jquery', 'woocommerce' ),
+ 'version' => $version,
+ ),
+ 'wc-cart' => array(
+ 'src' => self::get_asset_url( 'assets/js/frontend/cart' . $suffix . '.js' ),
+ 'deps' => array( 'jquery', 'woocommerce', 'wc-country-select', 'wc-address-i18n' ),
+ 'version' => $version,
+ ),
+ 'wc-cart-fragments' => array(
+ 'src' => self::get_asset_url( 'assets/js/frontend/cart-fragments' . $suffix . '.js' ),
+ 'deps' => array( 'jquery', 'js-cookie' ),
+ 'version' => $version,
+ ),
+ 'wc-checkout' => array(
+ 'src' => self::get_asset_url( 'assets/js/frontend/checkout' . $suffix . '.js' ),
+ 'deps' => array( 'jquery', 'woocommerce', 'wc-country-select', 'wc-address-i18n' ),
+ 'version' => $version,
+ ),
+ 'wc-country-select' => array(
+ 'src' => self::get_asset_url( 'assets/js/frontend/country-select' . $suffix . '.js' ),
+ 'deps' => array( 'jquery' ),
+ 'version' => $version,
+ ),
+ 'wc-credit-card-form' => array(
+ 'src' => self::get_asset_url( 'assets/js/frontend/credit-card-form' . $suffix . '.js' ),
+ 'deps' => array( 'jquery', 'jquery-payment' ),
+ 'version' => $version,
+ ),
+ 'wc-add-to-cart' => array(
+ 'src' => self::get_asset_url( 'assets/js/frontend/add-to-cart' . $suffix . '.js' ),
+ 'deps' => array( 'jquery', 'jquery-blockui' ),
+ 'version' => $version,
+ ),
+ 'wc-add-to-cart-variation' => array(
+ 'src' => self::get_asset_url( 'assets/js/frontend/add-to-cart-variation' . $suffix . '.js' ),
+ 'deps' => array( 'jquery', 'wp-util', 'jquery-blockui' ),
+ 'version' => $version,
+ ),
+ 'wc-geolocation' => array(
+ 'src' => self::get_asset_url( 'assets/js/frontend/geolocation' . $suffix . '.js' ),
+ 'deps' => array( 'jquery' ),
+ 'version' => $version,
+ ),
+ 'wc-lost-password' => array(
+ 'src' => self::get_asset_url( 'assets/js/frontend/lost-password' . $suffix . '.js' ),
+ 'deps' => array( 'jquery', 'woocommerce' ),
+ 'version' => $version,
+ ),
+ 'wc-password-strength-meter' => array(
+ 'src' => self::get_asset_url( 'assets/js/frontend/password-strength-meter' . $suffix . '.js' ),
+ 'deps' => array( 'jquery', 'password-strength-meter' ),
+ 'version' => $version,
+ ),
+ 'wc-single-product' => array(
+ 'src' => self::get_asset_url( 'assets/js/frontend/single-product' . $suffix . '.js' ),
+ 'deps' => array( 'jquery' ),
+ 'version' => $version,
+ ),
+ 'woocommerce' => array(
+ 'src' => self::get_asset_url( 'assets/js/frontend/woocommerce' . $suffix . '.js' ),
+ 'deps' => array( 'jquery', 'jquery-blockui', 'js-cookie' ),
+ 'version' => $version,
+ ),
+ 'zoom' => array(
+ 'src' => self::get_asset_url( 'assets/js/zoom/jquery.zoom' . $suffix . '.js' ),
+ 'deps' => array( 'jquery' ),
+ 'version' => '1.7.21',
+ ),
+ );
+ foreach ( $register_scripts as $name => $props ) {
+ self::register_script( $name, $props['src'], $props['deps'], $props['version'] );
+ }
+ }
+
+ /**
+ * Register all WC styles.
+ */
+ private static function register_styles() {
+ $version = Constants::get_constant( 'WC_VERSION' );
+
+ $register_styles = array(
+ 'photoswipe' => array(
+ 'src' => self::get_asset_url( 'assets/css/photoswipe/photoswipe.min.css' ),
+ 'deps' => array(),
+ 'version' => $version,
+ 'has_rtl' => false,
+ ),
+ 'photoswipe-default-skin' => array(
+ 'src' => self::get_asset_url( 'assets/css/photoswipe/default-skin/default-skin.min.css' ),
+ 'deps' => array( 'photoswipe' ),
+ 'version' => $version,
+ 'has_rtl' => false,
+ ),
+ 'select2' => array(
+ 'src' => self::get_asset_url( 'assets/css/select2.css' ),
+ 'deps' => array(),
+ 'version' => $version,
+ 'has_rtl' => false,
+ ),
+ 'woocommerce_prettyPhoto_css' => array( // deprecated.
+ 'src' => self::get_asset_url( 'assets/css/prettyPhoto.css' ),
+ 'deps' => array(),
+ 'version' => $version,
+ 'has_rtl' => true,
+ ),
+ );
+ foreach ( $register_styles as $name => $props ) {
+ self::register_style( $name, $props['src'], $props['deps'], $props['version'], 'all', $props['has_rtl'] );
+ }
+ }
+
+ /**
+ * Register/queue frontend scripts.
+ */
+ public static function load_scripts() {
+ global $post;
+
+ if ( ! did_action( 'before_woocommerce_init' ) ) {
+ return;
+ }
+
+ self::register_scripts();
+ self::register_styles();
+
+ if ( 'yes' === get_option( 'woocommerce_enable_ajax_add_to_cart' ) ) {
+ self::enqueue_script( 'wc-add-to-cart' );
+ }
+ if ( is_cart() ) {
+ self::enqueue_script( 'wc-cart' );
+ }
+ if ( is_cart() || is_checkout() || is_account_page() ) {
+ self::enqueue_script( 'selectWoo' );
+ self::enqueue_style( 'select2' );
+
+ // Password strength meter. Load in checkout, account login and edit account page.
+ if ( ( 'no' === get_option( 'woocommerce_registration_generate_password' ) && ! is_user_logged_in() ) || is_edit_account_page() || is_lost_password_page() ) {
+ self::enqueue_script( 'wc-password-strength-meter' );
+ }
+ }
+ if ( is_checkout() ) {
+ self::enqueue_script( 'wc-checkout' );
+ }
+ if ( is_add_payment_method_page() ) {
+ self::enqueue_script( 'wc-add-payment-method' );
+ }
+ if ( is_lost_password_page() ) {
+ self::enqueue_script( 'wc-lost-password' );
+ }
+
+ // Load gallery scripts on product pages only if supported.
+ if ( is_product() || ( ! empty( $post->post_content ) && strstr( $post->post_content, '[product_page' ) ) ) {
+ if ( current_theme_supports( 'wc-product-gallery-zoom' ) ) {
+ self::enqueue_script( 'zoom' );
+ }
+ if ( current_theme_supports( 'wc-product-gallery-slider' ) ) {
+ self::enqueue_script( 'flexslider' );
+ }
+ if ( current_theme_supports( 'wc-product-gallery-lightbox' ) ) {
+ self::enqueue_script( 'photoswipe-ui-default' );
+ self::enqueue_style( 'photoswipe-default-skin' );
+ add_action( 'wp_footer', 'woocommerce_photoswipe' );
+ }
+ self::enqueue_script( 'wc-single-product' );
+ }
+
+ if ( 'geolocation_ajax' === get_option( 'woocommerce_default_customer_address' ) ) {
+ $ua = strtolower( wc_get_user_agent() ); // Exclude common bots from geolocation by user agent.
+
+ if ( ! strstr( $ua, 'bot' ) && ! strstr( $ua, 'spider' ) && ! strstr( $ua, 'crawl' ) ) {
+ self::enqueue_script( 'wc-geolocation' );
+ }
+ }
+
+ // Global frontend scripts.
+ self::enqueue_script( 'woocommerce' );
+ self::enqueue_script( 'wc-cart-fragments' );
+
+ // CSS Styles.
+ $enqueue_styles = self::get_styles();
+ if ( $enqueue_styles ) {
+ foreach ( $enqueue_styles as $handle => $args ) {
+ if ( ! isset( $args['has_rtl'] ) ) {
+ $args['has_rtl'] = false;
+ }
+
+ self::enqueue_style( $handle, $args['src'], $args['deps'], $args['version'], $args['media'], $args['has_rtl'] );
+ }
+ }
+
+ // Placeholder style.
+ wp_register_style( 'woocommerce-inline', false ); // phpcs:ignore
+ wp_enqueue_style( 'woocommerce-inline' );
+
+ if ( true === wc_string_to_bool( get_option( 'woocommerce_checkout_highlight_required_fields', 'yes' ) ) ) {
+ wp_add_inline_style( 'woocommerce-inline', '.woocommerce form .form-row .required { visibility: visible; }' );
+ } else {
+ wp_add_inline_style( 'woocommerce-inline', '.woocommerce form .form-row .required { visibility: hidden; }' );
+ }
+ }
+
+ /**
+ * Localize a WC script once.
+ *
+ * @since 2.3.0 this needs less wp_script_is() calls due to https://core.trac.wordpress.org/ticket/28404 being added in WP 4.0.
+ * @param string $handle Script handle the data will be attached to.
+ */
+ private static function localize_script( $handle ) {
+ if ( ! in_array( $handle, self::$wp_localize_scripts, true ) && wp_script_is( $handle ) ) {
+ $data = self::get_script_data( $handle );
+
+ if ( ! $data ) {
+ return;
+ }
+
+ $name = str_replace( '-', '_', $handle ) . '_params';
+ self::$wp_localize_scripts[] = $handle;
+ wp_localize_script( $handle, $name, apply_filters( $name, $data ) );
+ }
+ }
+
+ /**
+ * Return data for script handles.
+ *
+ * @param string $handle Script handle the data will be attached to.
+ * @return array|bool
+ */
+ private static function get_script_data( $handle ) {
+ global $wp;
+
+ switch ( $handle ) {
+ case 'woocommerce':
+ $params = array(
+ 'ajax_url' => WC()->ajax_url(),
+ 'wc_ajax_url' => WC_AJAX::get_endpoint( '%%endpoint%%' ),
+ );
+ break;
+ case 'wc-geolocation':
+ $params = array(
+ 'wc_ajax_url' => WC_AJAX::get_endpoint( '%%endpoint%%' ),
+ 'home_url' => remove_query_arg( 'lang', home_url() ), // FIX for WPML compatibility.
+ 'is_available' => ! ( is_cart() || is_account_page() || is_checkout() || is_customize_preview() ) ? '1' : '0',
+ 'hash' => isset( $_GET['v'] ) ? wc_clean( wp_unslash( $_GET['v'] ) ) : '', // WPCS: input var ok, CSRF ok.
+ );
+ break;
+ case 'wc-single-product':
+ $params = array(
+ 'i18n_required_rating_text' => esc_attr__( 'Please select a rating', 'woocommerce' ),
+ 'review_rating_required' => wc_review_ratings_required() ? 'yes' : 'no',
+ 'flexslider' => apply_filters(
+ 'woocommerce_single_product_carousel_options',
+ array(
+ 'rtl' => is_rtl(),
+ 'animation' => 'slide',
+ 'smoothHeight' => true,
+ 'directionNav' => false,
+ 'controlNav' => 'thumbnails',
+ 'slideshow' => false,
+ 'animationSpeed' => 500,
+ 'animationLoop' => false, // Breaks photoswipe pagination if true.
+ 'allowOneSlide' => false,
+ )
+ ),
+ 'zoom_enabled' => apply_filters( 'woocommerce_single_product_zoom_enabled', get_theme_support( 'wc-product-gallery-zoom' ) ),
+ 'zoom_options' => apply_filters( 'woocommerce_single_product_zoom_options', array() ),
+ 'photoswipe_enabled' => apply_filters( 'woocommerce_single_product_photoswipe_enabled', get_theme_support( 'wc-product-gallery-lightbox' ) ),
+ 'photoswipe_options' => apply_filters(
+ 'woocommerce_single_product_photoswipe_options',
+ array(
+ 'shareEl' => false,
+ 'closeOnScroll' => false,
+ 'history' => false,
+ 'hideAnimationDuration' => 0,
+ 'showAnimationDuration' => 0,
+ )
+ ),
+ 'flexslider_enabled' => apply_filters( 'woocommerce_single_product_flexslider_enabled', get_theme_support( 'wc-product-gallery-slider' ) ),
+ );
+ break;
+ case 'wc-checkout':
+ $params = array(
+ 'ajax_url' => WC()->ajax_url(),
+ 'wc_ajax_url' => WC_AJAX::get_endpoint( '%%endpoint%%' ),
+ 'update_order_review_nonce' => wp_create_nonce( 'update-order-review' ),
+ 'apply_coupon_nonce' => wp_create_nonce( 'apply-coupon' ),
+ 'remove_coupon_nonce' => wp_create_nonce( 'remove-coupon' ),
+ 'option_guest_checkout' => get_option( 'woocommerce_enable_guest_checkout' ),
+ 'checkout_url' => WC_AJAX::get_endpoint( 'checkout' ),
+ 'is_checkout' => is_checkout() && empty( $wp->query_vars['order-pay'] ) && ! isset( $wp->query_vars['order-received'] ) ? 1 : 0,
+ 'debug_mode' => Constants::is_true( 'WP_DEBUG' ),
+ 'i18n_checkout_error' => esc_attr__( 'Error processing checkout. Please try again.', 'woocommerce' ),
+ );
+ break;
+ case 'wc-address-i18n':
+ $params = array(
+ 'locale' => wp_json_encode( WC()->countries->get_country_locale() ),
+ 'locale_fields' => wp_json_encode( WC()->countries->get_country_locale_field_selectors() ),
+ 'i18n_required_text' => esc_attr__( 'required', 'woocommerce' ),
+ 'i18n_optional_text' => esc_html__( 'optional', 'woocommerce' ),
+ );
+ break;
+ case 'wc-cart':
+ $params = array(
+ 'ajax_url' => WC()->ajax_url(),
+ 'wc_ajax_url' => WC_AJAX::get_endpoint( '%%endpoint%%' ),
+ 'update_shipping_method_nonce' => wp_create_nonce( 'update-shipping-method' ),
+ 'apply_coupon_nonce' => wp_create_nonce( 'apply-coupon' ),
+ 'remove_coupon_nonce' => wp_create_nonce( 'remove-coupon' ),
+ );
+ break;
+ case 'wc-cart-fragments':
+ $params = array(
+ 'ajax_url' => WC()->ajax_url(),
+ 'wc_ajax_url' => WC_AJAX::get_endpoint( '%%endpoint%%' ),
+ 'cart_hash_key' => apply_filters( 'woocommerce_cart_hash_key', 'wc_cart_hash_' . md5( get_current_blog_id() . '_' . get_site_url( get_current_blog_id(), '/' ) . get_template() ) ),
+ 'fragment_name' => apply_filters( 'woocommerce_cart_fragment_name', 'wc_fragments_' . md5( get_current_blog_id() . '_' . get_site_url( get_current_blog_id(), '/' ) . get_template() ) ),
+ 'request_timeout' => 5000,
+ );
+ break;
+ case 'wc-add-to-cart':
+ $params = array(
+ 'ajax_url' => WC()->ajax_url(),
+ 'wc_ajax_url' => WC_AJAX::get_endpoint( '%%endpoint%%' ),
+ 'i18n_view_cart' => esc_attr__( 'View cart', 'woocommerce' ),
+ 'cart_url' => apply_filters( 'woocommerce_add_to_cart_redirect', wc_get_cart_url(), null ),
+ 'is_cart' => is_cart(),
+ 'cart_redirect_after_add' => get_option( 'woocommerce_cart_redirect_after_add' ),
+ );
+ break;
+ case 'wc-add-to-cart-variation':
+ // We also need the wp.template for this script :).
+ wc_get_template( 'single-product/add-to-cart/variation.php' );
+
+ $params = array(
+ 'wc_ajax_url' => WC_AJAX::get_endpoint( '%%endpoint%%' ),
+ 'i18n_no_matching_variations_text' => esc_attr__( 'Sorry, no products matched your selection. Please choose a different combination.', 'woocommerce' ),
+ 'i18n_make_a_selection_text' => esc_attr__( 'Please select some product options before adding this product to your cart.', 'woocommerce' ),
+ 'i18n_unavailable_text' => esc_attr__( 'Sorry, this product is unavailable. Please choose a different combination.', 'woocommerce' ),
+ );
+ break;
+ case 'wc-country-select':
+ $params = array(
+ 'countries' => wp_json_encode( array_merge( WC()->countries->get_allowed_country_states(), WC()->countries->get_shipping_country_states() ) ),
+ 'i18n_select_state_text' => esc_attr__( 'Select an option…', 'woocommerce' ),
+ 'i18n_no_matches' => _x( 'No matches found', 'enhanced select', 'woocommerce' ),
+ 'i18n_ajax_error' => _x( 'Loading failed', 'enhanced select', 'woocommerce' ),
+ 'i18n_input_too_short_1' => _x( 'Please enter 1 or more characters', 'enhanced select', 'woocommerce' ),
+ 'i18n_input_too_short_n' => _x( 'Please enter %qty% or more characters', 'enhanced select', 'woocommerce' ),
+ 'i18n_input_too_long_1' => _x( 'Please delete 1 character', 'enhanced select', 'woocommerce' ),
+ 'i18n_input_too_long_n' => _x( 'Please delete %qty% characters', 'enhanced select', 'woocommerce' ),
+ 'i18n_selection_too_long_1' => _x( 'You can only select 1 item', 'enhanced select', 'woocommerce' ),
+ 'i18n_selection_too_long_n' => _x( 'You can only select %qty% items', 'enhanced select', 'woocommerce' ),
+ 'i18n_load_more' => _x( 'Loading more results…', 'enhanced select', 'woocommerce' ),
+ 'i18n_searching' => _x( 'Searching…', 'enhanced select', 'woocommerce' ),
+ );
+ break;
+ case 'wc-password-strength-meter':
+ $params = array(
+ 'min_password_strength' => apply_filters( 'woocommerce_min_password_strength', 3 ),
+ 'stop_checkout' => apply_filters( 'woocommerce_enforce_password_strength_meter_on_checkout', false ),
+ 'i18n_password_error' => esc_attr__( 'Please enter a stronger password.', 'woocommerce' ),
+ 'i18n_password_hint' => esc_attr( wp_get_password_hint() ),
+ );
+ break;
+ default:
+ $params = false;
+ }
+
+ $params = apply_filters_deprecated( $handle . '_params', array( $params ), '3.0.0', 'woocommerce_get_script_data' );
+
+ return apply_filters( 'woocommerce_get_script_data', $params, $handle );
+ }
+
+ /**
+ * Localize scripts only when enqueued.
+ */
+ public static function localize_printed_scripts() {
+ foreach ( self::$scripts as $handle ) {
+ self::localize_script( $handle );
+ }
+ }
+}
+
+WC_Frontend_Scripts::init();
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-geo-ip.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-geo-ip.php
new file mode 100644
index 0000000..c79be25
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-geo-ip.php
@@ -0,0 +1,1814 @@
+log( $level, $message, array( 'source' => 'geoip' ) );
+ }
+
+ /**
+ * Open geoip file.
+ *
+ * @param string $filename
+ * @param int $flags
+ */
+ public function geoip_open( $filename, $flags ) {
+ $this->flags = $flags;
+ if ( $this->flags & self::GEOIP_SHARED_MEMORY ) {
+ $this->shmid = @shmop_open( self::GEOIP_SHM_KEY, 'a', 0, 0 );
+ } else {
+ if ( $this->filehandle = fopen( $filename, 'rb' ) ) {
+ if ( $this->flags & self::GEOIP_MEMORY_CACHE ) {
+ $s_array = fstat( $this->filehandle );
+ $this->memory_buffer = fread( $this->filehandle, $s_array['size'] );
+ }
+ } else {
+ $this->log( 'GeoIP API: Can not open ' . $filename, 'error' );
+ }
+ }
+
+ $this->_setup_segments();
+ }
+
+ /**
+ * Setup segments.
+ *
+ * @return WC_Geo_IP instance
+ */
+ private function _setup_segments() {
+ $this->databaseType = self::GEOIP_COUNTRY_EDITION;
+ $this->record_length = self::STANDARD_RECORD_LENGTH;
+
+ if ( $this->flags & self::GEOIP_SHARED_MEMORY ) {
+ $offset = @shmop_size( $this->shmid ) - 3;
+
+ for ( $i = 0; $i < self::STRUCTURE_INFO_MAX_SIZE; $i++ ) {
+ $delim = @shmop_read( $this->shmid, $offset, 3 );
+ $offset += 3;
+
+ if ( ( chr( 255 ) . chr( 255 ) . chr( 255 ) ) == $delim ) {
+ $this->databaseType = ord( @shmop_read( $this->shmid, $offset, 1 ) );
+
+ if ( $this->databaseType >= 106 ) {
+ $this->databaseType -= 105;
+ }
+
+ $offset++;
+
+ if ( self::GEOIP_REGION_EDITION_REV0 == $this->databaseType ) {
+ $this->databaseSegments = self::GEOIP_STATE_BEGIN_REV0;
+ } elseif ( self::GEOIP_REGION_EDITION_REV1 == $this->databaseType ) {
+ $this->databaseSegments = self::GEOIP_STATE_BEGIN_REV1;
+ } elseif ( ( self::GEOIP_CITY_EDITION_REV0 == $this->databaseType )
+ || ( self::GEOIP_CITY_EDITION_REV1 == $this->databaseType )
+ || ( self::GEOIP_ORG_EDITION == $this->databaseType )
+ || ( self::GEOIP_ORG_EDITION_V6 == $this->databaseType )
+ || ( self::GEOIP_DOMAIN_EDITION == $this->databaseType )
+ || ( self::GEOIP_DOMAIN_EDITION_V6 == $this->databaseType )
+ || ( self::GEOIP_ISP_EDITION == $this->databaseType )
+ || ( self::GEOIP_ISP_EDITION_V6 == $this->databaseType )
+ || ( self::GEOIP_USERTYPE_EDITION == $this->databaseType )
+ || ( self::GEOIP_USERTYPE_EDITION_V6 == $this->databaseType )
+ || ( self::GEOIP_LOCATIONA_EDITION == $this->databaseType )
+ || ( self::GEOIP_ACCURACYRADIUS_EDITION == $this->databaseType )
+ || ( self::GEOIP_CITY_EDITION_REV0_V6 == $this->databaseType )
+ || ( self::GEOIP_CITY_EDITION_REV1_V6 == $this->databaseType )
+ || ( self::GEOIP_NETSPEED_EDITION_REV1 == $this->databaseType )
+ || ( self::GEOIP_NETSPEED_EDITION_REV1_V6 == $this->databaseType )
+ || ( self::GEOIP_ASNUM_EDITION == $this->databaseType )
+ || ( self::GEOIP_ASNUM_EDITION_V6 == $this->databaseType )
+ ) {
+ $this->databaseSegments = 0;
+ $buf = @shmop_read( $this->shmid, $offset, self::SEGMENT_RECORD_LENGTH );
+
+ for ( $j = 0; $j < self::SEGMENT_RECORD_LENGTH; $j++ ) {
+ $this->databaseSegments += ( ord( $buf[ $j ] ) << ( $j * 8 ) );
+ }
+
+ if ( ( self::GEOIP_ORG_EDITION == $this->databaseType )
+ || ( self::GEOIP_ORG_EDITION_V6 == $this->databaseType )
+ || ( self::GEOIP_DOMAIN_EDITION == $this->databaseType )
+ || ( self::GEOIP_DOMAIN_EDITION_V6 == $this->databaseType )
+ || ( self::GEOIP_ISP_EDITION == $this->databaseType )
+ || ( self::GEOIP_ISP_EDITION_V6 == $this->databaseType )
+ ) {
+ $this->record_length = self::ORG_RECORD_LENGTH;
+ }
+ }
+
+ break;
+ } else {
+ $offset -= 4;
+ }
+ }
+ if ( ( self::GEOIP_COUNTRY_EDITION == $this->databaseType )
+ || ( self::GEOIP_COUNTRY_EDITION_V6 == $this->databaseType )
+ || ( self::GEOIP_PROXY_EDITION == $this->databaseType )
+ || ( self::GEOIP_NETSPEED_EDITION == $this->databaseType )
+ ) {
+ $this->databaseSegments = self::GEOIP_COUNTRY_BEGIN;
+ }
+ } else {
+ $filepos = ftell( $this->filehandle );
+ fseek( $this->filehandle, -3, SEEK_END );
+
+ for ( $i = 0; $i < self::STRUCTURE_INFO_MAX_SIZE; $i++ ) {
+
+ $delim = fread( $this->filehandle, 3 );
+ if ( ( chr( 255 ) . chr( 255 ) . chr( 255 ) ) == $delim ) {
+
+ $this->databaseType = ord( fread( $this->filehandle, 1 ) );
+ if ( $this->databaseType >= 106 ) {
+ $this->databaseType -= 105;
+ }
+
+ if ( self::GEOIP_REGION_EDITION_REV0 == $this->databaseType ) {
+ $this->databaseSegments = self::GEOIP_STATE_BEGIN_REV0;
+ } elseif ( self::GEOIP_REGION_EDITION_REV1 == $this->databaseType ) {
+ $this->databaseSegments = self::GEOIP_STATE_BEGIN_REV1;
+ } elseif ( ( self::GEOIP_CITY_EDITION_REV0 == $this->databaseType )
+ || ( self::GEOIP_CITY_EDITION_REV1 == $this->databaseType )
+ || ( self::GEOIP_CITY_EDITION_REV0_V6 == $this->databaseType )
+ || ( self::GEOIP_CITY_EDITION_REV1_V6 == $this->databaseType )
+ || ( self::GEOIP_ORG_EDITION == $this->databaseType )
+ || ( self::GEOIP_DOMAIN_EDITION == $this->databaseType )
+ || ( self::GEOIP_ISP_EDITION == $this->databaseType )
+ || ( self::GEOIP_ORG_EDITION_V6 == $this->databaseType )
+ || ( self::GEOIP_DOMAIN_EDITION_V6 == $this->databaseType )
+ || ( self::GEOIP_ISP_EDITION_V6 == $this->databaseType )
+ || ( self::GEOIP_LOCATIONA_EDITION == $this->databaseType )
+ || ( self::GEOIP_ACCURACYRADIUS_EDITION == $this->databaseType )
+ || ( self::GEOIP_NETSPEED_EDITION_REV1 == $this->databaseType )
+ || ( self::GEOIP_NETSPEED_EDITION_REV1_V6 == $this->databaseType )
+ || ( self::GEOIP_USERTYPE_EDITION == $this->databaseType )
+ || ( self::GEOIP_USERTYPE_EDITION_V6 == $this->databaseType )
+ || ( self::GEOIP_ASNUM_EDITION == $this->databaseType )
+ || ( self::GEOIP_ASNUM_EDITION_V6 == $this->databaseType )
+ ) {
+ $this->databaseSegments = 0;
+ $buf = fread( $this->filehandle, self::SEGMENT_RECORD_LENGTH );
+
+ for ( $j = 0; $j < self::SEGMENT_RECORD_LENGTH; $j++ ) {
+ $this->databaseSegments += ( ord( $buf[ $j ] ) << ( $j * 8 ) );
+ }
+
+ if ( ( self::GEOIP_ORG_EDITION == $this->databaseType )
+ || ( self::GEOIP_DOMAIN_EDITION == $this->databaseType )
+ || ( self::GEOIP_ISP_EDITION == $this->databaseType )
+ || ( self::GEOIP_ORG_EDITION_V6 == $this->databaseType )
+ || ( self::GEOIP_DOMAIN_EDITION_V6 == $this->databaseType )
+ || ( self::GEOIP_ISP_EDITION_V6 == $this->databaseType )
+ ) {
+ $this->record_length = self::ORG_RECORD_LENGTH;
+ }
+ }
+
+ break;
+ } else {
+ fseek( $this->filehandle, -4, SEEK_CUR );
+ }
+ }
+
+ if ( ( self::GEOIP_COUNTRY_EDITION == $this->databaseType )
+ || ( self::GEOIP_COUNTRY_EDITION_V6 == $this->databaseType )
+ || ( self::GEOIP_PROXY_EDITION == $this->databaseType )
+ || ( self::GEOIP_NETSPEED_EDITION == $this->databaseType )
+ ) {
+ $this->databaseSegments = self::GEOIP_COUNTRY_BEGIN;
+ }
+
+ fseek( $this->filehandle, $filepos, SEEK_SET );
+ }
+
+ return $this;
+ }
+
+ /**
+ * Close geoip file.
+ *
+ * @return bool
+ */
+ public function geoip_close() {
+ if ( $this->flags & self::GEOIP_SHARED_MEMORY ) {
+ return true;
+ }
+
+ return fclose( $this->filehandle );
+ }
+
+ /**
+ * Common get record.
+ *
+ * @param string $seek_country
+ * @return WC_Geo_IP_Record instance
+ */
+ private function _common_get_record( $seek_country ) {
+ // workaround php's broken substr, strpos, etc handling with
+ // mbstring.func_overload and mbstring.internal_encoding
+ $mbExists = extension_loaded( 'mbstring' );
+ if ( $mbExists ) {
+ $enc = mb_internal_encoding();
+ mb_internal_encoding( 'ISO-8859-1' );
+ }
+
+ $record_pointer = $seek_country + ( 2 * $this->record_length - 1 ) * $this->databaseSegments;
+
+ if ( $this->flags & self::GEOIP_MEMORY_CACHE ) {
+ $record_buf = substr( $this->memory_buffer, $record_pointer, FULL_RECORD_LENGTH );
+ } elseif ( $this->flags & self::GEOIP_SHARED_MEMORY ) {
+ $record_buf = @shmop_read( $this->shmid, $record_pointer, FULL_RECORD_LENGTH );
+ } else {
+ fseek( $this->filehandle, $record_pointer, SEEK_SET );
+ $record_buf = fread( $this->filehandle, FULL_RECORD_LENGTH );
+ }
+
+ $record = new WC_Geo_IP_Record();
+ $record_buf_pos = 0;
+ $char = ord( substr( $record_buf, $record_buf_pos, 1 ) );
+ $record->country_code = $this->GEOIP_COUNTRY_CODES[ $char ];
+ $record->country_code3 = $this->GEOIP_COUNTRY_CODES3[ $char ];
+ $record->country_name = $this->GEOIP_COUNTRY_NAMES[ $char ];
+ $record->continent_code = $this->GEOIP_CONTINENT_CODES[ $char ];
+ $str_length = 0;
+
+ $record_buf_pos++;
+
+ // Get region
+ $char = ord( substr( $record_buf, $record_buf_pos + $str_length, 1 ) );
+ while ( 0 != $char ) {
+ $str_length++;
+ $char = ord( substr( $record_buf, $record_buf_pos + $str_length, 1 ) );
+ }
+
+ if ( $str_length > 0 ) {
+ $record->region = substr( $record_buf, $record_buf_pos, $str_length );
+ }
+
+ $record_buf_pos += $str_length + 1;
+ $str_length = 0;
+
+ // Get city
+ $char = ord( substr( $record_buf, $record_buf_pos + $str_length, 1 ) );
+ while ( 0 != $char ) {
+ $str_length++;
+ $char = ord( substr( $record_buf, $record_buf_pos + $str_length, 1 ) );
+ }
+
+ if ( $str_length > 0 ) {
+ $record->city = substr( $record_buf, $record_buf_pos, $str_length );
+ }
+
+ $record_buf_pos += $str_length + 1;
+ $str_length = 0;
+
+ // Get postal code
+ $char = ord( substr( $record_buf, $record_buf_pos + $str_length, 1 ) );
+ while ( 0 != $char ) {
+ $str_length++;
+ $char = ord( substr( $record_buf, $record_buf_pos + $str_length, 1 ) );
+ }
+
+ if ( $str_length > 0 ) {
+ $record->postal_code = substr( $record_buf, $record_buf_pos, $str_length );
+ }
+
+ $record_buf_pos += $str_length + 1;
+
+ // Get latitude and longitude
+ $latitude = 0;
+ $longitude = 0;
+ for ( $j = 0; $j < 3; ++$j ) {
+ $char = ord( substr( $record_buf, $record_buf_pos++, 1 ) );
+ $latitude += ( $char << ( $j * 8 ) );
+ }
+
+ $record->latitude = ( $latitude / 10000 ) - 180;
+
+ for ( $j = 0; $j < 3; ++$j ) {
+ $char = ord( substr( $record_buf, $record_buf_pos++, 1 ) );
+ $longitude += ( $char << ( $j * 8 ) );
+ }
+
+ $record->longitude = ( $longitude / 10000 ) - 180;
+
+ if ( self::GEOIP_CITY_EDITION_REV1 == $this->databaseType ) {
+ $metroarea_combo = 0;
+ if ( 'US' === $record->country_code ) {
+ for ( $j = 0; $j < 3; ++$j ) {
+ $char = ord( substr( $record_buf, $record_buf_pos++, 1 ) );
+ $metroarea_combo += ( $char << ( $j * 8 ) );
+ }
+
+ $record->metro_code = $record->dma_code = floor( $metroarea_combo / 1000 );
+ $record->area_code = $metroarea_combo % 1000;
+ }
+ }
+
+ if ( $mbExists ) {
+ mb_internal_encoding( $enc );
+ }
+
+ return $record;
+ }
+
+ /**
+ * Get record.
+ *
+ * @param int $ipnum
+ * @return WC_Geo_IP_Record instance
+ */
+ private function _get_record( $ipnum ) {
+ $seek_country = $this->_geoip_seek_country( $ipnum );
+ if ( $seek_country == $this->databaseSegments ) {
+ return null;
+ }
+
+ return $this->_common_get_record( $seek_country );
+ }
+
+ /**
+ * Seek country IPv6.
+ *
+ * @param int $ipnum
+ * @return string
+ */
+ public function _geoip_seek_country_v6( $ipnum ) {
+ // arrays from unpack start with offset 1
+ // yet another php mystery. array_merge work around
+ // this broken behaviour
+ $v6vec = array_merge( unpack( 'C16', $ipnum ) );
+
+ $offset = 0;
+ for ( $depth = 127; $depth >= 0; --$depth ) {
+ if ( $this->flags & self::GEOIP_MEMORY_CACHE ) {
+ $buf = $this->_safe_substr(
+ $this->memory_buffer,
+ 2 * $this->record_length * $offset,
+ 2 * $this->record_length
+ );
+ } elseif ( $this->flags & self::GEOIP_SHARED_MEMORY ) {
+ $buf = @shmop_read(
+ $this->shmid,
+ 2 * $this->record_length * $offset,
+ 2 * $this->record_length
+ );
+ } else {
+ if ( 0 != fseek( $this->filehandle, 2 * $this->record_length * $offset, SEEK_SET ) ) {
+ break;
+ }
+
+ $buf = fread( $this->filehandle, 2 * $this->record_length );
+ }
+ $x = array( 0, 0 );
+ for ( $i = 0; $i < 2; ++$i ) {
+ for ( $j = 0; $j < $this->record_length; ++$j ) {
+ $x[ $i ] += ord( $buf[ $this->record_length * $i + $j ] ) << ( $j * 8 );
+ }
+ }
+
+ $bnum = 127 - $depth;
+ $idx = $bnum >> 3;
+ $b_mask = 1 << ( $bnum & 7 ^ 7 );
+ if ( ( $v6vec[ $idx ] & $b_mask ) > 0 ) {
+ if ( $x[1] >= $this->databaseSegments ) {
+ return $x[1];
+ }
+ $offset = $x[1];
+ } else {
+ if ( $x[0] >= $this->databaseSegments ) {
+ return $x[0];
+ }
+ $offset = $x[0];
+ }
+ }
+
+ $this->log( 'GeoIP API: Error traversing database - perhaps it is corrupt?', 'error' );
+
+ return false;
+ }
+
+ /**
+ * Seek country.
+ *
+ * @param int $ipnum
+ * @return string
+ */
+ private function _geoip_seek_country( $ipnum ) {
+ $offset = 0;
+ for ( $depth = 31; $depth >= 0; --$depth ) {
+ if ( $this->flags & self::GEOIP_MEMORY_CACHE ) {
+ $buf = $this->_safe_substr(
+ $this->memory_buffer,
+ 2 * $this->record_length * $offset,
+ 2 * $this->record_length
+ );
+ } elseif ( $this->flags & self::GEOIP_SHARED_MEMORY ) {
+ $buf = @shmop_read(
+ $this->shmid,
+ 2 * $this->record_length * $offset,
+ 2 * $this->record_length
+ );
+ } else {
+ if ( 0 != fseek( $this->filehandle, 2 * $this->record_length * $offset, SEEK_SET ) ) {
+ break;
+ }
+
+ $buf = fread( $this->filehandle, 2 * $this->record_length );
+ }
+
+ $x = array( 0, 0 );
+ for ( $i = 0; $i < 2; ++$i ) {
+ for ( $j = 0; $j < $this->record_length; ++$j ) {
+ $x[ $i ] += ord( $buf[ $this->record_length * $i + $j ] ) << ( $j * 8 );
+ }
+ }
+ if ( $ipnum & ( 1 << $depth ) ) {
+ if ( $x[1] >= $this->databaseSegments ) {
+ return $x[1];
+ }
+
+ $offset = $x[1];
+ } else {
+ if ( $x[0] >= $this->databaseSegments ) {
+ return $x[0];
+ }
+
+ $offset = $x[0];
+ }
+ }
+
+ $this->log( 'GeoIP API: Error traversing database - perhaps it is corrupt?', 'error' );
+
+ return false;
+ }
+
+ /**
+ * Record by addr.
+ *
+ * @param string $addr
+ *
+ * @return WC_Geo_IP_Record
+ */
+ public function geoip_record_by_addr( $addr ) {
+ if ( null == $addr ) {
+ return 0;
+ }
+
+ $ipnum = ip2long( $addr );
+ return $this->_get_record( $ipnum );
+ }
+
+ /**
+ * Country ID by addr IPv6.
+ *
+ * @param string $addr
+ * @return int|bool
+ */
+ public function geoip_country_id_by_addr_v6( $addr ) {
+ if ( ! defined( 'AF_INET6' ) ) {
+ $this->log( 'GEOIP (geoip_country_id_by_addr_v6): PHP was compiled with --disable-ipv6 option' );
+ return false;
+ }
+ $ipnum = inet_pton( $addr );
+ return $this->_geoip_seek_country_v6( $ipnum ) - self::GEOIP_COUNTRY_BEGIN;
+ }
+
+ /**
+ * Country ID by addr.
+ *
+ * @param string $addr
+ * @return int
+ */
+ public function geoip_country_id_by_addr( $addr ) {
+ $ipnum = ip2long( $addr );
+ return $this->_geoip_seek_country( $ipnum ) - self::GEOIP_COUNTRY_BEGIN;
+ }
+
+ /**
+ * Country code by addr IPv6.
+ *
+ * @param string $addr
+ * @return string
+ */
+ public function geoip_country_code_by_addr_v6( $addr ) {
+ $country_id = $this->geoip_country_id_by_addr_v6( $addr );
+ if ( false !== $country_id && isset( $this->GEOIP_COUNTRY_CODES[ $country_id ] ) ) {
+ return $this->GEOIP_COUNTRY_CODES[ $country_id ];
+ }
+
+ return false;
+ }
+
+ /**
+ * Country code by addr.
+ *
+ * @param string $addr
+ * @return string
+ */
+ public function geoip_country_code_by_addr( $addr ) {
+ if ( self::GEOIP_CITY_EDITION_REV1 == $this->databaseType ) {
+ $record = $this->geoip_record_by_addr( $addr );
+ if ( false !== $record ) {
+ return $record->country_code;
+ }
+ } else {
+ $country_id = $this->geoip_country_id_by_addr( $addr );
+ if ( false !== $country_id && isset( $this->GEOIP_COUNTRY_CODES[ $country_id ] ) ) {
+ return $this->GEOIP_COUNTRY_CODES[ $country_id ];
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Encode string.
+ *
+ * @param string $string
+ * @param int $start
+ * @param int $length
+ * @return string
+ */
+ private function _safe_substr( $string, $start, $length ) {
+ // workaround php's broken substr, strpos, etc handling with
+ // mbstring.func_overload and mbstring.internal_encoding
+ $mb_exists = extension_loaded( 'mbstring' );
+
+ if ( $mb_exists ) {
+ $enc = mb_internal_encoding();
+ mb_internal_encoding( 'ISO-8859-1' );
+ }
+
+ $buf = substr( $string, $start, $length );
+
+ if ( $mb_exists ) {
+ mb_internal_encoding( $enc );
+ }
+
+ return $buf;
+ }
+}
+
+/**
+ * Geo IP Record class.
+ */
+class WC_Geo_IP_Record {
+
+ /**
+ * Country code.
+ *
+ * @var string
+ */
+ public $country_code;
+
+ /**
+ * 3 letters country code.
+ *
+ * @var string
+ */
+ public $country_code3;
+
+ /**
+ * Country name.
+ *
+ * @var string
+ */
+ public $country_name;
+
+ /**
+ * Region.
+ *
+ * @var string
+ */
+ public $region;
+
+ /**
+ * City.
+ *
+ * @var string
+ */
+ public $city;
+
+ /**
+ * Postal code.
+ *
+ * @var string
+ */
+ public $postal_code;
+
+ /**
+ * Latitude
+ *
+ * @var int
+ */
+ public $latitude;
+
+ /**
+ * Longitude.
+ *
+ * @var int
+ */
+ public $longitude;
+
+ /**
+ * Area code.
+ *
+ * @var int
+ */
+ public $area_code;
+
+ /**
+ * DMA Code.
+ *
+ * Metro and DMA code are the same.
+ * Use metro code instead.
+ *
+ * @var float
+ */
+ public $dma_code;
+
+ /**
+ * Metro code.
+ *
+ * @var float
+ */
+ public $metro_code;
+
+ /**
+ * Continent code.
+ *
+ * @var string
+ */
+ public $continent_code;
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-geolite-integration.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-geolite-integration.php
new file mode 100644
index 0000000..c661aa0
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-geolite-integration.php
@@ -0,0 +1,92 @@
+database = $database;
+ }
+
+ /**
+ * Get country 2-letters ISO by IP address.
+ * Returns empty string when not able to find any ISO code.
+ *
+ * @param string $ip_address User IP address.
+ * @return string
+ * @deprecated 3.9.0
+ */
+ public function get_country_iso( $ip_address ) {
+ wc_deprecated_function( 'get_country_iso', '3.9.0' );
+
+ $iso_code = '';
+
+ try {
+ $reader = new MaxMind\Db\Reader( $this->database ); // phpcs:ignore PHPCompatibility.LanguageConstructs.NewLanguageConstructs.t_ns_separatorFound
+ $data = $reader->get( $ip_address );
+
+ if ( isset( $data['country']['iso_code'] ) ) {
+ $iso_code = $data['country']['iso_code'];
+ }
+
+ $reader->close();
+ } catch ( Exception $e ) {
+ $this->log( $e->getMessage(), 'warning' );
+ }
+
+ return sanitize_text_field( strtoupper( $iso_code ) );
+ }
+
+ /**
+ * Logging method.
+ *
+ * @param string $message Log message.
+ * @param string $level Log level.
+ * Available options: 'emergency', 'alert',
+ * 'critical', 'error', 'warning', 'notice',
+ * 'info' and 'debug'.
+ * Defaults to 'info'.
+ */
+ private function log( $message, $level = 'info' ) {
+ if ( is_null( $this->log ) ) {
+ $this->log = wc_get_logger();
+ }
+
+ $this->log->log( $level, $message, array( 'source' => 'geoip' ) );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-geolocation.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-geolocation.php
new file mode 100644
index 0000000..97d9184
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-geolocation.php
@@ -0,0 +1,356 @@
+ 'http://api.ipify.org/',
+ 'ipecho' => 'http://ipecho.net/plain',
+ 'ident' => 'http://ident.me',
+ 'whatismyipaddress' => 'http://bot.whatismyipaddress.com',
+ );
+
+ /**
+ * API endpoints for geolocating an IP address
+ *
+ * @var array
+ */
+ private static $geoip_apis = array(
+ 'ipinfo.io' => 'https://ipinfo.io/%s/json',
+ 'ip-api.com' => 'http://ip-api.com/json/%s',
+ );
+
+ /**
+ * Check if geolocation is enabled.
+ *
+ * @since 3.4.0
+ * @param string $current_settings Current geolocation settings.
+ * @return bool
+ */
+ private static function is_geolocation_enabled( $current_settings ) {
+ return in_array( $current_settings, array( 'geolocation', 'geolocation_ajax' ), true );
+ }
+
+ /**
+ * Get current user IP Address.
+ *
+ * @return string
+ */
+ public static function get_ip_address() {
+ if ( isset( $_SERVER['HTTP_X_REAL_IP'] ) ) {
+ return sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_REAL_IP'] ) );
+ } elseif ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
+ // Proxy servers can send through this header like this: X-Forwarded-For: client1, proxy1, proxy2
+ // Make sure we always only send through the first IP in the list which should always be the client IP.
+ return (string) rest_is_ip_address( trim( current( preg_split( '/,/', sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) ) ) ) );
+ } elseif ( isset( $_SERVER['REMOTE_ADDR'] ) ) {
+ return sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) );
+ }
+ return '';
+ }
+
+ /**
+ * Get user IP Address using an external service.
+ * This can be used as a fallback for users on localhost where
+ * get_ip_address() will be a local IP and non-geolocatable.
+ *
+ * @return string
+ */
+ public static function get_external_ip_address() {
+ $external_ip_address = '0.0.0.0';
+
+ if ( '' !== self::get_ip_address() ) {
+ $transient_name = 'external_ip_address_' . self::get_ip_address();
+ $external_ip_address = get_transient( $transient_name );
+ }
+
+ if ( false === $external_ip_address ) {
+ $external_ip_address = '0.0.0.0';
+ $ip_lookup_services = apply_filters( 'woocommerce_geolocation_ip_lookup_apis', self::$ip_lookup_apis );
+ $ip_lookup_services_keys = array_keys( $ip_lookup_services );
+ shuffle( $ip_lookup_services_keys );
+
+ foreach ( $ip_lookup_services_keys as $service_name ) {
+ $service_endpoint = $ip_lookup_services[ $service_name ];
+ $response = wp_safe_remote_get( $service_endpoint, array( 'timeout' => 2 ) );
+
+ if ( ! is_wp_error( $response ) && rest_is_ip_address( $response['body'] ) ) {
+ $external_ip_address = apply_filters( 'woocommerce_geolocation_ip_lookup_api_response', wc_clean( $response['body'] ), $service_name );
+ break;
+ }
+ }
+
+ set_transient( $transient_name, $external_ip_address, WEEK_IN_SECONDS );
+ }
+
+ return $external_ip_address;
+ }
+
+ /**
+ * Geolocate an IP address.
+ *
+ * @param string $ip_address IP Address.
+ * @param bool $fallback If true, fallbacks to alternative IP detection (can be slower).
+ * @param bool $api_fallback If true, uses geolocation APIs if the database file doesn't exist (can be slower).
+ * @return array
+ */
+ public static function geolocate_ip( $ip_address = '', $fallback = false, $api_fallback = true ) {
+ // Filter to allow custom geolocation of the IP address.
+ $country_code = apply_filters( 'woocommerce_geolocate_ip', false, $ip_address, $fallback, $api_fallback );
+
+ if ( false !== $country_code ) {
+ return array(
+ 'country' => $country_code,
+ 'state' => '',
+ 'city' => '',
+ 'postcode' => '',
+ );
+ }
+
+ if ( empty( $ip_address ) ) {
+ $ip_address = self::get_ip_address();
+ }
+
+ $country_code = self::get_country_code_from_headers();
+
+ /**
+ * Get geolocation filter.
+ *
+ * @since 3.9.0
+ * @param array $geolocation Geolocation data, including country, state, city, and postcode.
+ * @param string $ip_address IP Address.
+ */
+ $geolocation = apply_filters(
+ 'woocommerce_get_geolocation',
+ array(
+ 'country' => $country_code,
+ 'state' => '',
+ 'city' => '',
+ 'postcode' => '',
+ ),
+ $ip_address
+ );
+
+ // If we still haven't found a country code, let's consider doing an API lookup.
+ if ( '' === $geolocation['country'] && $api_fallback ) {
+ $geolocation['country'] = self::geolocate_via_api( $ip_address );
+ }
+
+ // It's possible that we're in a local environment, in which case the geolocation needs to be done from the
+ // external address.
+ if ( '' === $geolocation['country'] && $fallback ) {
+ $external_ip_address = self::get_external_ip_address();
+
+ // Only bother with this if the external IP differs.
+ if ( '0.0.0.0' !== $external_ip_address && $external_ip_address !== $ip_address ) {
+ return self::geolocate_ip( $external_ip_address, false, $api_fallback );
+ }
+ }
+
+ return array(
+ 'country' => $geolocation['country'],
+ 'state' => $geolocation['state'],
+ 'city' => $geolocation['city'],
+ 'postcode' => $geolocation['postcode'],
+ );
+ }
+
+ /**
+ * Path to our local db.
+ *
+ * @deprecated 3.9.0
+ * @param string $deprecated Deprecated since 3.4.0.
+ * @return string
+ */
+ public static function get_local_database_path( $deprecated = '2' ) {
+ wc_deprecated_function( 'WC_Geolocation::get_local_database_path', '3.9.0' );
+ $integration = wc()->integrations->get_integration( 'maxmind_geolocation' );
+ return $integration->get_database_service()->get_database_path();
+ }
+
+ /**
+ * Update geoip database.
+ *
+ * @deprecated 3.9.0
+ * Extract files with PharData. Tool built into PHP since 5.3.
+ */
+ public static function update_database() {
+ wc_deprecated_function( 'WC_Geolocation::update_database', '3.9.0' );
+ $integration = wc()->integrations->get_integration( 'maxmind_geolocation' );
+ $integration->update_database();
+ }
+
+ /**
+ * Fetches the country code from the request headers, if one is available.
+ *
+ * @since 3.9.0
+ * @return string The country code pulled from the headers, or empty string if one was not found.
+ */
+ private static function get_country_code_from_headers() {
+ $country_code = '';
+
+ $headers = array(
+ 'MM_COUNTRY_CODE',
+ 'GEOIP_COUNTRY_CODE',
+ 'HTTP_CF_IPCOUNTRY',
+ 'HTTP_X_COUNTRY_CODE',
+ );
+
+ foreach ( $headers as $header ) {
+ if ( empty( $_SERVER[ $header ] ) ) {
+ continue;
+ }
+
+ $country_code = strtoupper( sanitize_text_field( wp_unslash( $_SERVER[ $header ] ) ) );
+ break;
+ }
+
+ return $country_code;
+ }
+
+ /**
+ * Use APIs to Geolocate the user.
+ *
+ * Geolocation APIs can be added through the use of the woocommerce_geolocation_geoip_apis filter.
+ * Provide a name=>value pair for service-slug=>endpoint.
+ *
+ * If APIs are defined, one will be chosen at random to fulfil the request. After completing, the result
+ * will be cached in a transient.
+ *
+ * @param string $ip_address IP address.
+ * @return string
+ */
+ private static function geolocate_via_api( $ip_address ) {
+ $country_code = get_transient( 'geoip_' . $ip_address );
+
+ if ( false === $country_code ) {
+ $geoip_services = apply_filters( 'woocommerce_geolocation_geoip_apis', self::$geoip_apis );
+
+ if ( empty( $geoip_services ) ) {
+ return '';
+ }
+
+ $geoip_services_keys = array_keys( $geoip_services );
+
+ shuffle( $geoip_services_keys );
+
+ foreach ( $geoip_services_keys as $service_name ) {
+ $service_endpoint = $geoip_services[ $service_name ];
+ $response = wp_safe_remote_get( sprintf( $service_endpoint, $ip_address ), array( 'timeout' => 2 ) );
+
+ if ( ! is_wp_error( $response ) && $response['body'] ) {
+ switch ( $service_name ) {
+ case 'ipinfo.io':
+ $data = json_decode( $response['body'] );
+ $country_code = isset( $data->country ) ? $data->country : '';
+ break;
+ case 'ip-api.com':
+ $data = json_decode( $response['body'] );
+ $country_code = isset( $data->countryCode ) ? $data->countryCode : ''; // @codingStandardsIgnoreLine
+ break;
+ default:
+ $country_code = apply_filters( 'woocommerce_geolocation_geoip_response_' . $service_name, '', $response['body'] );
+ break;
+ }
+
+ $country_code = sanitize_text_field( strtoupper( $country_code ) );
+
+ if ( $country_code ) {
+ break;
+ }
+ }
+ }
+
+ set_transient( 'geoip_' . $ip_address, $country_code, WEEK_IN_SECONDS );
+ }
+
+ return $country_code;
+ }
+
+ /**
+ * Hook in geolocation functionality.
+ *
+ * @deprecated 3.9.0
+ * @return null
+ */
+ public static function init() {
+ wc_deprecated_function( 'WC_Geolocation::init', '3.9.0' );
+ return null;
+ }
+
+ /**
+ * Prevent geolocation via MaxMind when using legacy versions of php.
+ *
+ * @deprecated 3.9.0
+ * @since 3.4.0
+ * @param string $default_customer_address current value.
+ * @return string
+ */
+ public static function disable_geolocation_on_legacy_php( $default_customer_address ) {
+ wc_deprecated_function( 'WC_Geolocation::disable_geolocation_on_legacy_php', '3.9.0' );
+
+ if ( self::is_geolocation_enabled( $default_customer_address ) ) {
+ $default_customer_address = 'base';
+ }
+
+ return $default_customer_address;
+ }
+
+ /**
+ * Maybe trigger a DB update for the first time.
+ *
+ * @deprecated 3.9.0
+ * @param string $new_value New value.
+ * @param string $old_value Old value.
+ * @return string
+ */
+ public static function maybe_update_database( $new_value, $old_value ) {
+ wc_deprecated_function( 'WC_Geolocation::maybe_update_database', '3.9.0' );
+ if ( $new_value !== $old_value && self::is_geolocation_enabled( $new_value ) ) {
+ self::update_database();
+ }
+
+ return $new_value;
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-https.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-https.php
new file mode 100644
index 0000000..84e3aed
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-https.php
@@ -0,0 +1,138 @@
+ array(
+ 'wc_update_200_file_paths',
+ 'wc_update_200_permalinks',
+ 'wc_update_200_subcat_display',
+ 'wc_update_200_taxrates',
+ 'wc_update_200_line_items',
+ 'wc_update_200_images',
+ 'wc_update_200_db_version',
+ ),
+ '2.0.9' => array(
+ 'wc_update_209_brazillian_state',
+ 'wc_update_209_db_version',
+ ),
+ '2.1.0' => array(
+ 'wc_update_210_remove_pages',
+ 'wc_update_210_file_paths',
+ 'wc_update_210_db_version',
+ ),
+ '2.2.0' => array(
+ 'wc_update_220_shipping',
+ 'wc_update_220_order_status',
+ 'wc_update_220_variations',
+ 'wc_update_220_attributes',
+ 'wc_update_220_db_version',
+ ),
+ '2.3.0' => array(
+ 'wc_update_230_options',
+ 'wc_update_230_db_version',
+ ),
+ '2.4.0' => array(
+ 'wc_update_240_options',
+ 'wc_update_240_shipping_methods',
+ 'wc_update_240_api_keys',
+ 'wc_update_240_refunds',
+ 'wc_update_240_db_version',
+ ),
+ '2.4.1' => array(
+ 'wc_update_241_variations',
+ 'wc_update_241_db_version',
+ ),
+ '2.5.0' => array(
+ 'wc_update_250_currency',
+ 'wc_update_250_db_version',
+ ),
+ '2.6.0' => array(
+ 'wc_update_260_options',
+ 'wc_update_260_termmeta',
+ 'wc_update_260_zones',
+ 'wc_update_260_zone_methods',
+ 'wc_update_260_refunds',
+ 'wc_update_260_db_version',
+ ),
+ '3.0.0' => array(
+ 'wc_update_300_grouped_products',
+ 'wc_update_300_settings',
+ 'wc_update_300_product_visibility',
+ 'wc_update_300_db_version',
+ ),
+ '3.1.0' => array(
+ 'wc_update_310_downloadable_products',
+ 'wc_update_310_old_comments',
+ 'wc_update_310_db_version',
+ ),
+ '3.1.2' => array(
+ 'wc_update_312_shop_manager_capabilities',
+ 'wc_update_312_db_version',
+ ),
+ '3.2.0' => array(
+ 'wc_update_320_mexican_states',
+ 'wc_update_320_db_version',
+ ),
+ '3.3.0' => array(
+ 'wc_update_330_image_options',
+ 'wc_update_330_webhooks',
+ 'wc_update_330_product_stock_status',
+ 'wc_update_330_set_default_product_cat',
+ 'wc_update_330_clear_transients',
+ 'wc_update_330_set_paypal_sandbox_credentials',
+ 'wc_update_330_db_version',
+ ),
+ '3.4.0' => array(
+ 'wc_update_340_states',
+ 'wc_update_340_state',
+ 'wc_update_340_last_active',
+ 'wc_update_340_db_version',
+ ),
+ '3.4.3' => array(
+ 'wc_update_343_cleanup_foreign_keys',
+ 'wc_update_343_db_version',
+ ),
+ '3.4.4' => array(
+ 'wc_update_344_recreate_roles',
+ 'wc_update_344_db_version',
+ ),
+ '3.5.0' => array(
+ 'wc_update_350_reviews_comment_type',
+ 'wc_update_350_db_version',
+ ),
+ '3.5.2' => array(
+ 'wc_update_352_drop_download_log_fk',
+ ),
+ '3.5.4' => array(
+ 'wc_update_354_modify_shop_manager_caps',
+ 'wc_update_354_db_version',
+ ),
+ '3.6.0' => array(
+ 'wc_update_360_product_lookup_tables',
+ 'wc_update_360_term_meta',
+ 'wc_update_360_downloadable_product_permissions_index',
+ 'wc_update_360_db_version',
+ ),
+ '3.7.0' => array(
+ 'wc_update_370_tax_rate_classes',
+ 'wc_update_370_mro_std_currency',
+ 'wc_update_370_db_version',
+ ),
+ '3.9.0' => array(
+ 'wc_update_390_move_maxmind_database',
+ 'wc_update_390_change_geolocation_database_update_cron',
+ 'wc_update_390_db_version',
+ ),
+ '4.0.0' => array(
+ 'wc_update_product_lookup_tables',
+ 'wc_update_400_increase_size_of_column',
+ 'wc_update_400_reset_action_scheduler_migration_status',
+ 'wc_update_400_db_version',
+ ),
+ '4.4.0' => array(
+ 'wc_update_440_insert_attribute_terms_for_variable_products',
+ 'wc_update_440_db_version',
+ ),
+ '4.5.0' => array(
+ 'wc_update_450_sanitize_coupons_code',
+ 'wc_update_450_db_version',
+ ),
+ );
+
+ /**
+ * Hook in tabs.
+ */
+ public static function init() {
+ add_action( 'init', array( __CLASS__, 'check_version' ), 5 );
+ add_action( 'init', array( __CLASS__, 'manual_database_update' ), 20 );
+ add_action( 'admin_init', array( __CLASS__, 'wc_admin_db_update_notice' ) );
+ add_action( 'woocommerce_run_update_callback', array( __CLASS__, 'run_update_callback' ) );
+ add_action( 'admin_init', array( __CLASS__, 'install_actions' ) );
+ add_filter( 'plugin_action_links_' . WC_PLUGIN_BASENAME, array( __CLASS__, 'plugin_action_links' ) );
+ add_filter( 'plugin_row_meta', array( __CLASS__, 'plugin_row_meta' ), 10, 2 );
+ add_filter( 'wpmu_drop_tables', array( __CLASS__, 'wpmu_drop_tables' ) );
+ add_filter( 'cron_schedules', array( __CLASS__, 'cron_schedules' ) );
+ }
+
+ /**
+ * Check WooCommerce version and run the updater is required.
+ *
+ * This check is done on all requests and runs if the versions do not match.
+ */
+ public static function check_version() {
+ if ( ! Constants::is_defined( 'IFRAME_REQUEST' ) && version_compare( get_option( 'woocommerce_version' ), WC()->version, '<' ) ) {
+ self::install();
+ do_action( 'woocommerce_updated' );
+ }
+ }
+
+ /**
+ * Performan manual database update when triggered by WooCommerce System Tools.
+ *
+ * @since 3.6.5
+ */
+ public static function manual_database_update() {
+ $blog_id = get_current_blog_id();
+
+ add_action( 'wp_' . $blog_id . '_wc_updater_cron', array( __CLASS__, 'run_manual_database_update' ) );
+ }
+
+ /**
+ * Add WC Admin based db update notice.
+ *
+ * @since 4.0.0
+ */
+ public static function wc_admin_db_update_notice() {
+ if (
+ WC()->is_wc_admin_active() &&
+ false !== get_option( 'woocommerce_admin_install_timestamp' )
+ ) {
+ new WC_Notes_Run_Db_Update();
+ }
+ }
+
+ /**
+ * Run manual database update.
+ */
+ public static function run_manual_database_update() {
+ self::update();
+ }
+
+ /**
+ * Run an update callback when triggered by ActionScheduler.
+ *
+ * @since 3.6.0
+ * @param string $callback Callback name.
+ */
+ public static function run_update_callback( $callback ) {
+ include_once dirname( __FILE__ ) . '/wc-update-functions.php';
+
+ if ( is_callable( $callback ) ) {
+ self::run_update_callback_start( $callback );
+ $result = (bool) call_user_func( $callback );
+ self::run_update_callback_end( $callback, $result );
+ }
+ }
+
+ /**
+ * Triggered when a callback will run.
+ *
+ * @since 3.6.0
+ * @param string $callback Callback name.
+ */
+ protected static function run_update_callback_start( $callback ) {
+ wc_maybe_define_constant( 'WC_UPDATING', true );
+ }
+
+ /**
+ * Triggered when a callback has ran.
+ *
+ * @since 3.6.0
+ * @param string $callback Callback name.
+ * @param bool $result Return value from callback. Non-false need to run again.
+ */
+ protected static function run_update_callback_end( $callback, $result ) {
+ if ( $result ) {
+ WC()->queue()->add(
+ 'woocommerce_run_update_callback',
+ array(
+ 'update_callback' => $callback,
+ ),
+ 'woocommerce-db-updates'
+ );
+ }
+ }
+
+ /**
+ * Install actions when a update button is clicked within the admin area.
+ *
+ * This function is hooked into admin_init to affect admin only.
+ */
+ public static function install_actions() {
+ if ( ! empty( $_GET['do_update_woocommerce'] ) ) { // WPCS: input var ok.
+ check_admin_referer( 'wc_db_update', 'wc_db_update_nonce' );
+ self::update();
+ WC_Admin_Notices::add_notice( 'update', true );
+ }
+ }
+
+ /**
+ * Install WC.
+ */
+ public static function install() {
+ if ( ! is_blog_installed() ) {
+ return;
+ }
+
+ // Check if we are not already running this routine.
+ if ( 'yes' === get_transient( 'wc_installing' ) ) {
+ return;
+ }
+
+ // If we made it till here nothing is running yet, lets set the transient now.
+ set_transient( 'wc_installing', 'yes', MINUTE_IN_SECONDS * 10 );
+ wc_maybe_define_constant( 'WC_INSTALLING', true );
+
+ WC()->wpdb_table_fix();
+ self::remove_admin_notices();
+ self::create_tables();
+ self::verify_base_tables();
+ self::create_options();
+ self::create_roles();
+ self::setup_environment();
+ self::create_terms();
+ self::create_cron_jobs();
+ self::create_files();
+ self::maybe_create_pages();
+ self::maybe_set_activation_transients();
+ self::update_wc_version();
+ self::maybe_update_db_version();
+
+ delete_transient( 'wc_installing' );
+
+ do_action( 'woocommerce_flush_rewrite_rules' );
+ do_action( 'woocommerce_installed' );
+ }
+
+ /**
+ * Check if all the base tables are present.
+ *
+ * @param bool $modify_notice Whether to modify notice based on if all tables are present.
+ * @param bool $execute Whether to execute get_schema queries as well.
+ *
+ * @return array List of querues.
+ */
+ public static function verify_base_tables( $modify_notice = true, $execute = false ) {
+ require_once ABSPATH . 'wp-admin/includes/upgrade.php';
+
+ if ( $execute ) {
+ self::create_tables();
+ }
+ $queries = dbDelta( self::get_schema(), false );
+ $missing_tables = array();
+ foreach ( $queries as $table_name => $result ) {
+ if ( "Created table $table_name" === $result ) {
+ $missing_tables[] = $table_name;
+ }
+ }
+
+ if ( 0 < count( $missing_tables ) ) {
+ if ( $modify_notice ) {
+ WC_Admin_Notices::add_notice( 'base_tables_missing' );
+ }
+ update_option( 'woocommerce_schema_missing_tables', $missing_tables );
+ } else {
+ if ( $modify_notice ) {
+ WC_Admin_Notices::remove_notice( 'base_tables_missing' );
+ }
+ update_option( 'woocommerce_schema_version', WC()->db_version );
+ delete_option( 'woocommerce_schema_missing_tables' );
+ }
+ return $missing_tables;
+ }
+
+ /**
+ * Reset any notices added to admin.
+ *
+ * @since 3.2.0
+ */
+ private static function remove_admin_notices() {
+ include_once dirname( __FILE__ ) . '/admin/class-wc-admin-notices.php';
+ WC_Admin_Notices::remove_all_notices();
+ }
+
+ /**
+ * Setup WC environment - post types, taxonomies, endpoints.
+ *
+ * @since 3.2.0
+ */
+ private static function setup_environment() {
+ WC_Post_types::register_post_types();
+ WC_Post_types::register_taxonomies();
+ WC()->query->init_query_vars();
+ WC()->query->add_endpoints();
+ WC_API::add_endpoint();
+ WC_Auth::add_endpoint();
+ }
+
+ /**
+ * Is this a brand new WC install?
+ *
+ * A brand new install has no version yet. Also treat empty installs as 'new'.
+ *
+ * @since 3.2.0
+ * @return boolean
+ */
+ public static function is_new_install() {
+ $product_count = array_sum( (array) wp_count_posts( 'product' ) );
+
+ return is_null( get_option( 'woocommerce_version', null ) ) || ( 0 === $product_count && -1 === wc_get_page_id( 'shop' ) );
+ }
+
+ /**
+ * Is a DB update needed?
+ *
+ * @since 3.2.0
+ * @return boolean
+ */
+ public static function needs_db_update() {
+ $current_db_version = get_option( 'woocommerce_db_version', null );
+ $updates = self::get_db_update_callbacks();
+ $update_versions = array_keys( $updates );
+ usort( $update_versions, 'version_compare' );
+
+ return ! is_null( $current_db_version ) && version_compare( $current_db_version, end( $update_versions ), '<' );
+ }
+
+ /**
+ * See if we need to set redirect transients for activation or not.
+ *
+ * @since 4.6.0
+ */
+ private static function maybe_set_activation_transients() {
+ if ( self::is_new_install() ) {
+ set_transient( '_wc_activation_redirect', 1, 30 );
+ }
+ }
+
+ /**
+ * See if we need to show or run database updates during install.
+ *
+ * @since 3.2.0
+ */
+ private static function maybe_update_db_version() {
+ if ( self::needs_db_update() ) {
+ if ( apply_filters( 'woocommerce_enable_auto_update_db', false ) ) {
+ self::update();
+ } else {
+ WC_Admin_Notices::add_notice( 'update', true );
+ }
+ } else {
+ self::update_db_version();
+ }
+ }
+
+ /**
+ * Update WC version to current.
+ */
+ private static function update_wc_version() {
+ update_option( 'woocommerce_version', WC()->version );
+ }
+
+ /**
+ * Get list of DB update callbacks.
+ *
+ * @since 3.0.0
+ * @return array
+ */
+ public static function get_db_update_callbacks() {
+ return self::$db_updates;
+ }
+
+ /**
+ * Push all needed DB updates to the queue for processing.
+ */
+ private static function update() {
+ $current_db_version = get_option( 'woocommerce_db_version' );
+ $loop = 0;
+
+ foreach ( self::get_db_update_callbacks() as $version => $update_callbacks ) {
+ if ( version_compare( $current_db_version, $version, '<' ) ) {
+ foreach ( $update_callbacks as $update_callback ) {
+ WC()->queue()->schedule_single(
+ time() + $loop,
+ 'woocommerce_run_update_callback',
+ array(
+ 'update_callback' => $update_callback,
+ ),
+ 'woocommerce-db-updates'
+ );
+ $loop++;
+ }
+ }
+ }
+ }
+
+ /**
+ * Update DB version to current.
+ *
+ * @param string|null $version New WooCommerce DB version or null.
+ */
+ public static function update_db_version( $version = null ) {
+ update_option( 'woocommerce_db_version', is_null( $version ) ? WC()->version : $version );
+ }
+
+ /**
+ * Add more cron schedules.
+ *
+ * @param array $schedules List of WP scheduled cron jobs.
+ *
+ * @return array
+ */
+ public static function cron_schedules( $schedules ) {
+ $schedules['monthly'] = array(
+ 'interval' => 2635200,
+ 'display' => __( 'Monthly', 'woocommerce' ),
+ );
+ $schedules['fifteendays'] = array(
+ 'interval' => 1296000,
+ 'display' => __( 'Every 15 Days', 'woocommerce' ),
+ );
+ return $schedules;
+ }
+
+ /**
+ * Create cron jobs (clear them first).
+ */
+ private static function create_cron_jobs() {
+ wp_clear_scheduled_hook( 'woocommerce_scheduled_sales' );
+ wp_clear_scheduled_hook( 'woocommerce_cancel_unpaid_orders' );
+ wp_clear_scheduled_hook( 'woocommerce_cleanup_sessions' );
+ wp_clear_scheduled_hook( 'woocommerce_cleanup_personal_data' );
+ wp_clear_scheduled_hook( 'woocommerce_cleanup_logs' );
+ wp_clear_scheduled_hook( 'woocommerce_geoip_updater' );
+ wp_clear_scheduled_hook( 'woocommerce_tracker_send_event' );
+
+ $ve = get_option( 'gmt_offset' ) > 0 ? '-' : '+';
+
+ wp_schedule_event( strtotime( '00:00 tomorrow ' . $ve . absint( get_option( 'gmt_offset' ) ) . ' HOURS' ), 'daily', 'woocommerce_scheduled_sales' );
+
+ $held_duration = get_option( 'woocommerce_hold_stock_minutes', '60' );
+
+ if ( '' !== $held_duration ) {
+ wp_schedule_single_event( time() + ( absint( $held_duration ) * 60 ), 'woocommerce_cancel_unpaid_orders' );
+ }
+
+ // Delay the first run of `woocommerce_cleanup_personal_data` by 10 seconds
+ // so it doesn't occur in the same request. WooCommerce Admin also schedules
+ // a daily cron that gets lost due to a race condition. WC_Privacy's background
+ // processing instance updates the cron schedule from within a cron job.
+ wp_schedule_event( time() + 10, 'daily', 'woocommerce_cleanup_personal_data' );
+ wp_schedule_event( time() + ( 3 * HOUR_IN_SECONDS ), 'daily', 'woocommerce_cleanup_logs' );
+ wp_schedule_event( time() + ( 6 * HOUR_IN_SECONDS ), 'twicedaily', 'woocommerce_cleanup_sessions' );
+ wp_schedule_event( time() + MINUTE_IN_SECONDS, 'fifteendays', 'woocommerce_geoip_updater' );
+ wp_schedule_event( time() + 10, apply_filters( 'woocommerce_tracker_event_recurrence', 'daily' ), 'woocommerce_tracker_send_event' );
+ }
+
+ /**
+ * Create pages on installation.
+ */
+ public static function maybe_create_pages() {
+ if ( empty( get_option( 'woocommerce_db_version' ) ) ) {
+ self::create_pages();
+ }
+ }
+
+ /**
+ * Create pages that the plugin relies on, storing page IDs in variables.
+ */
+ public static function create_pages() {
+ include_once dirname( __FILE__ ) . '/admin/wc-admin-functions.php';
+
+ $pages = apply_filters(
+ 'woocommerce_create_pages',
+ array(
+ 'shop' => array(
+ 'name' => _x( 'shop', 'Page slug', 'woocommerce' ),
+ 'title' => _x( 'Shop', 'Page title', 'woocommerce' ),
+ 'content' => '',
+ ),
+ 'cart' => array(
+ 'name' => _x( 'cart', 'Page slug', 'woocommerce' ),
+ 'title' => _x( 'Cart', 'Page title', 'woocommerce' ),
+ 'content' => '[' . apply_filters( 'woocommerce_cart_shortcode_tag', 'woocommerce_cart' ) . ']',
+ ),
+ 'checkout' => array(
+ 'name' => _x( 'checkout', 'Page slug', 'woocommerce' ),
+ 'title' => _x( 'Checkout', 'Page title', 'woocommerce' ),
+ 'content' => '[' . apply_filters( 'woocommerce_checkout_shortcode_tag', 'woocommerce_checkout' ) . ']',
+ ),
+ 'myaccount' => array(
+ 'name' => _x( 'my-account', 'Page slug', 'woocommerce' ),
+ 'title' => _x( 'My account', 'Page title', 'woocommerce' ),
+ 'content' => '[' . apply_filters( 'woocommerce_my_account_shortcode_tag', 'woocommerce_my_account' ) . ']',
+ ),
+ )
+ );
+
+ foreach ( $pages as $key => $page ) {
+ wc_create_page( esc_sql( $page['name'] ), 'woocommerce_' . $key . '_page_id', $page['title'], $page['content'], ! empty( $page['parent'] ) ? wc_get_page_id( $page['parent'] ) : '' );
+ }
+ }
+
+ /**
+ * Default options.
+ *
+ * Sets up the default options used on the settings page.
+ */
+ private static function create_options() {
+ // Include settings so that we can run through defaults.
+ include_once dirname( __FILE__ ) . '/admin/class-wc-admin-settings.php';
+
+ $settings = WC_Admin_Settings::get_settings_pages();
+
+ foreach ( $settings as $section ) {
+ if ( ! method_exists( $section, 'get_settings' ) ) {
+ continue;
+ }
+ $subsections = array_unique( array_merge( array( '' ), array_keys( $section->get_sections() ) ) );
+
+ foreach ( $subsections as $subsection ) {
+ foreach ( $section->get_settings( $subsection ) as $value ) {
+ if ( isset( $value['default'] ) && isset( $value['id'] ) ) {
+ $autoload = isset( $value['autoload'] ) ? (bool) $value['autoload'] : true;
+ add_option( $value['id'], $value['default'], '', ( $autoload ? 'yes' : 'no' ) );
+ }
+ }
+ }
+ }
+
+ // Define other defaults if not in setting screens.
+ add_option( 'woocommerce_single_image_width', '600', '', 'yes' );
+ add_option( 'woocommerce_thumbnail_image_width', '300', '', 'yes' );
+ add_option( 'woocommerce_checkout_highlight_required_fields', 'yes', '', 'yes' );
+ add_option( 'woocommerce_demo_store', 'no', '', 'no' );
+
+ // Define initial tax classes.
+ WC_Tax::create_tax_class( __( 'Reduced rate', 'woocommerce' ) );
+ WC_Tax::create_tax_class( __( 'Zero rate', 'woocommerce' ) );
+ }
+
+ /**
+ * Add the default terms for WC taxonomies - product types and order statuses. Modify this at your own risk.
+ */
+ public static function create_terms() {
+ $taxonomies = array(
+ 'product_type' => array(
+ 'simple',
+ 'grouped',
+ 'variable',
+ 'external',
+ ),
+ 'product_visibility' => array(
+ 'exclude-from-search',
+ 'exclude-from-catalog',
+ 'featured',
+ 'outofstock',
+ 'rated-1',
+ 'rated-2',
+ 'rated-3',
+ 'rated-4',
+ 'rated-5',
+ ),
+ );
+
+ foreach ( $taxonomies as $taxonomy => $terms ) {
+ foreach ( $terms as $term ) {
+ if ( ! get_term_by( 'name', $term, $taxonomy ) ) { // @codingStandardsIgnoreLine.
+ wp_insert_term( $term, $taxonomy );
+ }
+ }
+ }
+
+ $woocommerce_default_category = (int) get_option( 'default_product_cat', 0 );
+
+ if ( ! $woocommerce_default_category || ! term_exists( $woocommerce_default_category, 'product_cat' ) ) {
+ $default_product_cat_id = 0;
+ $default_product_cat_slug = sanitize_title( _x( 'Uncategorized', 'Default category slug', 'woocommerce' ) );
+ $default_product_cat = get_term_by( 'slug', $default_product_cat_slug, 'product_cat' ); // @codingStandardsIgnoreLine.
+
+ if ( $default_product_cat ) {
+ $default_product_cat_id = absint( $default_product_cat->term_taxonomy_id );
+ } else {
+ $result = wp_insert_term( _x( 'Uncategorized', 'Default category slug', 'woocommerce' ), 'product_cat', array( 'slug' => $default_product_cat_slug ) );
+
+ if ( ! is_wp_error( $result ) && ! empty( $result['term_taxonomy_id'] ) ) {
+ $default_product_cat_id = absint( $result['term_taxonomy_id'] );
+ }
+ }
+
+ if ( $default_product_cat_id ) {
+ update_option( 'default_product_cat', $default_product_cat_id );
+ }
+ }
+ }
+
+ /**
+ * Set up the database tables which the plugin needs to function.
+ * WARNING: If you are modifying this method, make sure that its safe to call regardless of the state of database.
+ *
+ * This is called from `install` method and is executed in-sync when WC is installed or updated. This can also be called optionally from `verify_base_tables`.
+ *
+ * TODO: Add all crucial tables that we have created from workers in the past.
+ *
+ * Tables:
+ * woocommerce_attribute_taxonomies - Table for storing attribute taxonomies - these are user defined
+ * woocommerce_downloadable_product_permissions - Table for storing user and guest download permissions.
+ * KEY(order_id, product_id, download_id) used for organizing downloads on the My Account page
+ * woocommerce_order_items - Order line items are stored in a table to make them easily queryable for reports
+ * woocommerce_order_itemmeta - Order line item meta is stored in a table for storing extra data.
+ * woocommerce_tax_rates - Tax Rates are stored inside 2 tables making tax queries simple and efficient.
+ * woocommerce_tax_rate_locations - Each rate can be applied to more than one postcode/city hence the second table.
+ */
+ private static function create_tables() {
+ global $wpdb;
+
+ $wpdb->hide_errors();
+
+ require_once ABSPATH . 'wp-admin/includes/upgrade.php';
+
+ /**
+ * Before updating with DBDELTA, remove any primary keys which could be
+ * modified due to schema updates.
+ */
+ if ( $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->prefix}woocommerce_downloadable_product_permissions';" ) ) {
+ if ( ! $wpdb->get_var( "SHOW COLUMNS FROM `{$wpdb->prefix}woocommerce_downloadable_product_permissions` LIKE 'permission_id';" ) ) {
+ $wpdb->query( "ALTER TABLE {$wpdb->prefix}woocommerce_downloadable_product_permissions DROP PRIMARY KEY, ADD `permission_id` BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT;" );
+ }
+ }
+
+ /**
+ * Change wp_woocommerce_sessions schema to use a bigint auto increment field instead of char(32) field as
+ * the primary key as it is not a good practice to use a char(32) field as the primary key of a table and as
+ * there were reports of issues with this table (see https://github.com/woocommerce/woocommerce/issues/20912).
+ *
+ * This query needs to run before dbDelta() as this WP function is not able to handle primary key changes
+ * (see https://github.com/woocommerce/woocommerce/issues/21534 and https://core.trac.wordpress.org/ticket/40357).
+ */
+ if ( $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->prefix}woocommerce_sessions'" ) ) {
+ if ( ! $wpdb->get_var( "SHOW KEYS FROM {$wpdb->prefix}woocommerce_sessions WHERE Key_name = 'PRIMARY' AND Column_name = 'session_id'" ) ) {
+ $wpdb->query(
+ "ALTER TABLE `{$wpdb->prefix}woocommerce_sessions` DROP PRIMARY KEY, DROP KEY `session_id`, ADD PRIMARY KEY(`session_id`), ADD UNIQUE KEY(`session_key`)"
+ );
+ }
+ }
+
+ dbDelta( self::get_schema() );
+
+ $index_exists = $wpdb->get_row( "SHOW INDEX FROM {$wpdb->comments} WHERE column_name = 'comment_type' and key_name = 'woo_idx_comment_type'" );
+
+ if ( is_null( $index_exists ) ) {
+ // Add an index to the field comment_type to improve the response time of the query
+ // used by WC_Comments::wp_count_comments() to get the number of comments by type.
+ $wpdb->query( "ALTER TABLE {$wpdb->comments} ADD INDEX woo_idx_comment_type (comment_type)" );
+ }
+
+ // Get tables data types and check it matches before adding constraint.
+ $download_log_columns = $wpdb->get_results( "SHOW COLUMNS FROM {$wpdb->prefix}wc_download_log WHERE Field = 'permission_id'", ARRAY_A );
+ $download_log_column_type = '';
+ if ( isset( $download_log_columns[0]['Type'] ) ) {
+ $download_log_column_type = $download_log_columns[0]['Type'];
+ }
+
+ $download_permissions_columns = $wpdb->get_results( "SHOW COLUMNS FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE Field = 'permission_id'", ARRAY_A );
+ $download_permissions_column_type = '';
+ if ( isset( $download_permissions_columns[0]['Type'] ) ) {
+ $download_permissions_column_type = $download_permissions_columns[0]['Type'];
+ }
+
+ // Add constraint to download logs if the columns matches.
+ if ( ! empty( $download_permissions_column_type ) && ! empty( $download_log_column_type ) && $download_permissions_column_type === $download_log_column_type ) {
+ $fk_result = $wpdb->get_row( "SHOW CREATE TABLE {$wpdb->prefix}wc_download_log" );
+ if ( false === strpos( $fk_result->{'Create Table'}, "fk_{$wpdb->prefix}wc_download_log_permission_id" ) ) {
+ $wpdb->query(
+ "ALTER TABLE `{$wpdb->prefix}wc_download_log`
+ ADD CONSTRAINT `fk_{$wpdb->prefix}wc_download_log_permission_id`
+ FOREIGN KEY (`permission_id`)
+ REFERENCES `{$wpdb->prefix}woocommerce_downloadable_product_permissions` (`permission_id`) ON DELETE CASCADE;"
+ );
+ }
+ }
+
+ // Clear table caches.
+ delete_transient( 'wc_attribute_taxonomies' );
+ }
+
+ /**
+ * Get Table schema.
+ *
+ * See https://github.com/woocommerce/woocommerce/wiki/Database-Description/
+ *
+ * A note on indexes; Indexes have a maximum size of 767 bytes. Historically, we haven't need to be concerned about that.
+ * As of WordPress 4.2, however, we moved to utf8mb4, which uses 4 bytes per character. This means that an index which
+ * used to have room for floor(767/3) = 255 characters, now only has room for floor(767/4) = 191 characters.
+ *
+ * Changing indexes may cause duplicate index notices in logs due to https://core.trac.wordpress.org/ticket/34870 but dropping
+ * indexes first causes too much load on some servers/larger DB.
+ *
+ * When adding or removing a table, make sure to update the list of tables in WC_Install::get_tables().
+ *
+ * @return string
+ */
+ private static function get_schema() {
+ global $wpdb;
+
+ $collate = '';
+
+ if ( $wpdb->has_cap( 'collation' ) ) {
+ $collate = $wpdb->get_charset_collate();
+ }
+
+ /*
+ * Indexes have a maximum size of 767 bytes. Historically, we haven't need to be concerned about that.
+ * As of WP 4.2, however, they moved to utf8mb4, which uses 4 bytes per character. This means that an index which
+ * used to have room for floor(767/3) = 255 characters, now only has room for floor(767/4) = 191 characters.
+ */
+ $max_index_length = 191;
+
+ $tables = "
+CREATE TABLE {$wpdb->prefix}woocommerce_sessions (
+ session_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
+ session_key char(32) NOT NULL,
+ session_value longtext NOT NULL,
+ session_expiry BIGINT UNSIGNED NOT NULL,
+ PRIMARY KEY (session_id),
+ UNIQUE KEY session_key (session_key)
+) $collate;
+CREATE TABLE {$wpdb->prefix}woocommerce_api_keys (
+ key_id BIGINT UNSIGNED NOT NULL auto_increment,
+ user_id BIGINT UNSIGNED NOT NULL,
+ description varchar(200) NULL,
+ permissions varchar(10) NOT NULL,
+ consumer_key char(64) NOT NULL,
+ consumer_secret char(43) NOT NULL,
+ nonces longtext NULL,
+ truncated_key char(7) NOT NULL,
+ last_access datetime NULL default null,
+ PRIMARY KEY (key_id),
+ KEY consumer_key (consumer_key),
+ KEY consumer_secret (consumer_secret)
+) $collate;
+CREATE TABLE {$wpdb->prefix}woocommerce_attribute_taxonomies (
+ attribute_id BIGINT UNSIGNED NOT NULL auto_increment,
+ attribute_name varchar(200) NOT NULL,
+ attribute_label varchar(200) NULL,
+ attribute_type varchar(20) NOT NULL,
+ attribute_orderby varchar(20) NOT NULL,
+ attribute_public int(1) NOT NULL DEFAULT 1,
+ PRIMARY KEY (attribute_id),
+ KEY attribute_name (attribute_name(20))
+) $collate;
+CREATE TABLE {$wpdb->prefix}woocommerce_downloadable_product_permissions (
+ permission_id BIGINT UNSIGNED NOT NULL auto_increment,
+ download_id varchar(36) NOT NULL,
+ product_id BIGINT UNSIGNED NOT NULL,
+ order_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
+ order_key varchar(200) NOT NULL,
+ user_email varchar(200) NOT NULL,
+ user_id BIGINT UNSIGNED NULL,
+ downloads_remaining varchar(9) NULL,
+ access_granted datetime NOT NULL default '0000-00-00 00:00:00',
+ access_expires datetime NULL default null,
+ download_count BIGINT UNSIGNED NOT NULL DEFAULT 0,
+ PRIMARY KEY (permission_id),
+ KEY download_order_key_product (product_id,order_id,order_key(16),download_id),
+ KEY download_order_product (download_id,order_id,product_id),
+ KEY order_id (order_id),
+ KEY user_order_remaining_expires (user_id,order_id,downloads_remaining,access_expires)
+) $collate;
+CREATE TABLE {$wpdb->prefix}woocommerce_order_items (
+ order_item_id BIGINT UNSIGNED NOT NULL auto_increment,
+ order_item_name TEXT NOT NULL,
+ order_item_type varchar(200) NOT NULL DEFAULT '',
+ order_id BIGINT UNSIGNED NOT NULL,
+ PRIMARY KEY (order_item_id),
+ KEY order_id (order_id)
+) $collate;
+CREATE TABLE {$wpdb->prefix}woocommerce_order_itemmeta (
+ meta_id BIGINT UNSIGNED NOT NULL auto_increment,
+ order_item_id BIGINT UNSIGNED NOT NULL,
+ meta_key varchar(255) default NULL,
+ meta_value longtext NULL,
+ PRIMARY KEY (meta_id),
+ KEY order_item_id (order_item_id),
+ KEY meta_key (meta_key(32))
+) $collate;
+CREATE TABLE {$wpdb->prefix}woocommerce_tax_rates (
+ tax_rate_id BIGINT UNSIGNED NOT NULL auto_increment,
+ tax_rate_country varchar(2) NOT NULL DEFAULT '',
+ tax_rate_state varchar(200) NOT NULL DEFAULT '',
+ tax_rate varchar(8) NOT NULL DEFAULT '',
+ tax_rate_name varchar(200) NOT NULL DEFAULT '',
+ tax_rate_priority BIGINT UNSIGNED NOT NULL,
+ tax_rate_compound int(1) NOT NULL DEFAULT 0,
+ tax_rate_shipping int(1) NOT NULL DEFAULT 1,
+ tax_rate_order BIGINT UNSIGNED NOT NULL,
+ tax_rate_class varchar(200) NOT NULL DEFAULT '',
+ PRIMARY KEY (tax_rate_id),
+ KEY tax_rate_country (tax_rate_country),
+ KEY tax_rate_state (tax_rate_state(2)),
+ KEY tax_rate_class (tax_rate_class(10)),
+ KEY tax_rate_priority (tax_rate_priority)
+) $collate;
+CREATE TABLE {$wpdb->prefix}woocommerce_tax_rate_locations (
+ location_id BIGINT UNSIGNED NOT NULL auto_increment,
+ location_code varchar(200) NOT NULL,
+ tax_rate_id BIGINT UNSIGNED NOT NULL,
+ location_type varchar(40) NOT NULL,
+ PRIMARY KEY (location_id),
+ KEY tax_rate_id (tax_rate_id),
+ KEY location_type_code (location_type(10),location_code(20))
+) $collate;
+CREATE TABLE {$wpdb->prefix}woocommerce_shipping_zones (
+ zone_id BIGINT UNSIGNED NOT NULL auto_increment,
+ zone_name varchar(200) NOT NULL,
+ zone_order BIGINT UNSIGNED NOT NULL,
+ PRIMARY KEY (zone_id)
+) $collate;
+CREATE TABLE {$wpdb->prefix}woocommerce_shipping_zone_locations (
+ location_id BIGINT UNSIGNED NOT NULL auto_increment,
+ zone_id BIGINT UNSIGNED NOT NULL,
+ location_code varchar(200) NOT NULL,
+ location_type varchar(40) NOT NULL,
+ PRIMARY KEY (location_id),
+ KEY location_id (location_id),
+ KEY location_type_code (location_type(10),location_code(20))
+) $collate;
+CREATE TABLE {$wpdb->prefix}woocommerce_shipping_zone_methods (
+ zone_id BIGINT UNSIGNED NOT NULL,
+ instance_id BIGINT UNSIGNED NOT NULL auto_increment,
+ method_id varchar(200) NOT NULL,
+ method_order BIGINT UNSIGNED NOT NULL,
+ is_enabled tinyint(1) NOT NULL DEFAULT '1',
+ PRIMARY KEY (instance_id)
+) $collate;
+CREATE TABLE {$wpdb->prefix}woocommerce_payment_tokens (
+ token_id BIGINT UNSIGNED NOT NULL auto_increment,
+ gateway_id varchar(200) NOT NULL,
+ token text NOT NULL,
+ user_id BIGINT UNSIGNED NOT NULL DEFAULT '0',
+ type varchar(200) NOT NULL,
+ is_default tinyint(1) NOT NULL DEFAULT '0',
+ PRIMARY KEY (token_id),
+ KEY user_id (user_id)
+) $collate;
+CREATE TABLE {$wpdb->prefix}woocommerce_payment_tokenmeta (
+ meta_id BIGINT UNSIGNED NOT NULL auto_increment,
+ payment_token_id BIGINT UNSIGNED NOT NULL,
+ meta_key varchar(255) NULL,
+ meta_value longtext NULL,
+ PRIMARY KEY (meta_id),
+ KEY payment_token_id (payment_token_id),
+ KEY meta_key (meta_key(32))
+) $collate;
+CREATE TABLE {$wpdb->prefix}woocommerce_log (
+ log_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
+ timestamp datetime NOT NULL,
+ level smallint(4) NOT NULL,
+ source varchar(200) NOT NULL,
+ message longtext NOT NULL,
+ context longtext NULL,
+ PRIMARY KEY (log_id),
+ KEY level (level)
+) $collate;
+CREATE TABLE {$wpdb->prefix}wc_webhooks (
+ webhook_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
+ status varchar(200) NOT NULL,
+ name text NOT NULL,
+ user_id BIGINT UNSIGNED NOT NULL,
+ delivery_url text NOT NULL,
+ secret text NOT NULL,
+ topic varchar(200) NOT NULL,
+ date_created datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ date_created_gmt datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ date_modified datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ date_modified_gmt datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ api_version smallint(4) NOT NULL,
+ failure_count smallint(10) NOT NULL DEFAULT '0',
+ pending_delivery tinyint(1) NOT NULL DEFAULT '0',
+ PRIMARY KEY (webhook_id),
+ KEY user_id (user_id)
+) $collate;
+CREATE TABLE {$wpdb->prefix}wc_download_log (
+ download_log_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
+ timestamp datetime NOT NULL,
+ permission_id BIGINT UNSIGNED NOT NULL,
+ user_id BIGINT UNSIGNED NULL,
+ user_ip_address VARCHAR(100) NULL DEFAULT '',
+ PRIMARY KEY (download_log_id),
+ KEY permission_id (permission_id),
+ KEY timestamp (timestamp)
+) $collate;
+CREATE TABLE {$wpdb->prefix}wc_product_meta_lookup (
+ `product_id` bigint(20) NOT NULL,
+ `sku` varchar(100) NULL default '',
+ `virtual` tinyint(1) NULL default 0,
+ `downloadable` tinyint(1) NULL default 0,
+ `min_price` decimal(19,4) NULL default NULL,
+ `max_price` decimal(19,4) NULL default NULL,
+ `onsale` tinyint(1) NULL default 0,
+ `stock_quantity` double NULL default NULL,
+ `stock_status` varchar(100) NULL default 'instock',
+ `rating_count` bigint(20) NULL default 0,
+ `average_rating` decimal(3,2) NULL default 0.00,
+ `total_sales` bigint(20) NULL default 0,
+ `tax_status` varchar(100) NULL default 'taxable',
+ `tax_class` varchar(100) NULL default '',
+ PRIMARY KEY (`product_id`),
+ KEY `virtual` (`virtual`),
+ KEY `downloadable` (`downloadable`),
+ KEY `stock_status` (`stock_status`),
+ KEY `stock_quantity` (`stock_quantity`),
+ KEY `onsale` (`onsale`),
+ KEY min_max_price (`min_price`, `max_price`)
+) $collate;
+CREATE TABLE {$wpdb->prefix}wc_tax_rate_classes (
+ tax_rate_class_id BIGINT UNSIGNED NOT NULL auto_increment,
+ name varchar(200) NOT NULL DEFAULT '',
+ slug varchar(200) NOT NULL DEFAULT '',
+ PRIMARY KEY (tax_rate_class_id),
+ UNIQUE KEY slug (slug($max_index_length))
+) $collate;
+CREATE TABLE {$wpdb->prefix}wc_reserved_stock (
+ `order_id` bigint(20) NOT NULL,
+ `product_id` bigint(20) NOT NULL,
+ `stock_quantity` double NOT NULL DEFAULT 0,
+ `timestamp` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ `expires` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ PRIMARY KEY (`order_id`, `product_id`)
+) $collate;
+ ";
+
+ return $tables;
+ }
+
+ /**
+ * Return a list of WooCommerce tables. Used to make sure all WC tables are dropped when uninstalling the plugin
+ * in a single site or multi site environment.
+ *
+ * @return array WC tables.
+ */
+ public static function get_tables() {
+ global $wpdb;
+
+ $tables = array(
+ "{$wpdb->prefix}wc_download_log",
+ "{$wpdb->prefix}wc_product_meta_lookup",
+ "{$wpdb->prefix}wc_tax_rate_classes",
+ "{$wpdb->prefix}wc_webhooks",
+ "{$wpdb->prefix}woocommerce_api_keys",
+ "{$wpdb->prefix}woocommerce_attribute_taxonomies",
+ "{$wpdb->prefix}woocommerce_downloadable_product_permissions",
+ "{$wpdb->prefix}woocommerce_log",
+ "{$wpdb->prefix}woocommerce_order_itemmeta",
+ "{$wpdb->prefix}woocommerce_order_items",
+ "{$wpdb->prefix}woocommerce_payment_tokenmeta",
+ "{$wpdb->prefix}woocommerce_payment_tokens",
+ "{$wpdb->prefix}woocommerce_sessions",
+ "{$wpdb->prefix}woocommerce_shipping_zone_locations",
+ "{$wpdb->prefix}woocommerce_shipping_zone_methods",
+ "{$wpdb->prefix}woocommerce_shipping_zones",
+ "{$wpdb->prefix}woocommerce_tax_rate_locations",
+ "{$wpdb->prefix}woocommerce_tax_rates",
+ "{$wpdb->prefix}wc_reserved_stock",
+ );
+
+ /**
+ * Filter the list of known WooCommerce tables.
+ *
+ * If WooCommerce plugins need to add new tables, they can inject them here.
+ *
+ * @param array $tables An array of WooCommerce-specific database table names.
+ */
+ $tables = apply_filters( 'woocommerce_install_get_tables', $tables );
+
+ return $tables;
+ }
+
+ /**
+ * Drop WooCommerce tables.
+ *
+ * @return void
+ */
+ public static function drop_tables() {
+ global $wpdb;
+
+ $tables = self::get_tables();
+
+ foreach ( $tables as $table ) {
+ $wpdb->query( "DROP TABLE IF EXISTS {$table}" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
+ }
+ }
+
+ /**
+ * Uninstall tables when MU blog is deleted.
+ *
+ * @param array $tables List of tables that will be deleted by WP.
+ *
+ * @return string[]
+ */
+ public static function wpmu_drop_tables( $tables ) {
+ return array_merge( $tables, self::get_tables() );
+ }
+
+ /**
+ * Create roles and capabilities.
+ */
+ public static function create_roles() {
+ global $wp_roles;
+
+ if ( ! class_exists( 'WP_Roles' ) ) {
+ return;
+ }
+
+ if ( ! isset( $wp_roles ) ) {
+ $wp_roles = new WP_Roles(); // @codingStandardsIgnoreLine
+ }
+
+ // Dummy gettext calls to get strings in the catalog.
+ /* translators: user role */
+ _x( 'Customer', 'User role', 'woocommerce' );
+ /* translators: user role */
+ _x( 'Shop manager', 'User role', 'woocommerce' );
+
+ // Customer role.
+ add_role(
+ 'customer',
+ 'Customer',
+ array(
+ 'read' => true,
+ )
+ );
+
+ // Shop manager role.
+ add_role(
+ 'shop_manager',
+ 'Shop manager',
+ array(
+ 'level_9' => true,
+ 'level_8' => true,
+ 'level_7' => true,
+ 'level_6' => true,
+ 'level_5' => true,
+ 'level_4' => true,
+ 'level_3' => true,
+ 'level_2' => true,
+ 'level_1' => true,
+ 'level_0' => true,
+ 'read' => true,
+ 'read_private_pages' => true,
+ 'read_private_posts' => true,
+ 'edit_posts' => true,
+ 'edit_pages' => true,
+ 'edit_published_posts' => true,
+ 'edit_published_pages' => true,
+ 'edit_private_pages' => true,
+ 'edit_private_posts' => true,
+ 'edit_others_posts' => true,
+ 'edit_others_pages' => true,
+ 'publish_posts' => true,
+ 'publish_pages' => true,
+ 'delete_posts' => true,
+ 'delete_pages' => true,
+ 'delete_private_pages' => true,
+ 'delete_private_posts' => true,
+ 'delete_published_pages' => true,
+ 'delete_published_posts' => true,
+ 'delete_others_posts' => true,
+ 'delete_others_pages' => true,
+ 'manage_categories' => true,
+ 'manage_links' => true,
+ 'moderate_comments' => true,
+ 'upload_files' => true,
+ 'export' => true,
+ 'import' => true,
+ 'list_users' => true,
+ 'edit_theme_options' => true,
+ )
+ );
+
+ $capabilities = self::get_core_capabilities();
+
+ foreach ( $capabilities as $cap_group ) {
+ foreach ( $cap_group as $cap ) {
+ $wp_roles->add_cap( 'shop_manager', $cap );
+ $wp_roles->add_cap( 'administrator', $cap );
+ }
+ }
+ }
+
+ /**
+ * Get capabilities for WooCommerce - these are assigned to admin/shop manager during installation or reset.
+ *
+ * @return array
+ */
+ public static function get_core_capabilities() {
+ $capabilities = array();
+
+ $capabilities['core'] = array(
+ 'manage_woocommerce',
+ 'view_woocommerce_reports',
+ );
+
+ $capability_types = array( 'product', 'shop_order', 'shop_coupon' );
+
+ foreach ( $capability_types as $capability_type ) {
+
+ $capabilities[ $capability_type ] = array(
+ // Post type.
+ "edit_{$capability_type}",
+ "read_{$capability_type}",
+ "delete_{$capability_type}",
+ "edit_{$capability_type}s",
+ "edit_others_{$capability_type}s",
+ "publish_{$capability_type}s",
+ "read_private_{$capability_type}s",
+ "delete_{$capability_type}s",
+ "delete_private_{$capability_type}s",
+ "delete_published_{$capability_type}s",
+ "delete_others_{$capability_type}s",
+ "edit_private_{$capability_type}s",
+ "edit_published_{$capability_type}s",
+
+ // Terms.
+ "manage_{$capability_type}_terms",
+ "edit_{$capability_type}_terms",
+ "delete_{$capability_type}_terms",
+ "assign_{$capability_type}_terms",
+ );
+ }
+
+ return $capabilities;
+ }
+
+ /**
+ * Remove WooCommerce roles.
+ */
+ public static function remove_roles() {
+ global $wp_roles;
+
+ if ( ! class_exists( 'WP_Roles' ) ) {
+ return;
+ }
+
+ if ( ! isset( $wp_roles ) ) {
+ $wp_roles = new WP_Roles(); // @codingStandardsIgnoreLine
+ }
+
+ $capabilities = self::get_core_capabilities();
+
+ foreach ( $capabilities as $cap_group ) {
+ foreach ( $cap_group as $cap ) {
+ $wp_roles->remove_cap( 'shop_manager', $cap );
+ $wp_roles->remove_cap( 'administrator', $cap );
+ }
+ }
+
+ remove_role( 'customer' );
+ remove_role( 'shop_manager' );
+ }
+
+ /**
+ * Create files/directories.
+ */
+ private static function create_files() {
+ // Bypass if filesystem is read-only and/or non-standard upload system is used.
+ if ( apply_filters( 'woocommerce_install_skip_create_files', false ) ) {
+ return;
+ }
+
+ // Install files and folders for uploading files and prevent hotlinking.
+ $upload_dir = wp_get_upload_dir();
+ $download_method = get_option( 'woocommerce_file_download_method', 'force' );
+
+ $files = array(
+ array(
+ 'base' => $upload_dir['basedir'] . '/woocommerce_uploads',
+ 'file' => 'index.html',
+ 'content' => '',
+ ),
+ array(
+ 'base' => WC_LOG_DIR,
+ 'file' => '.htaccess',
+ 'content' => 'deny from all',
+ ),
+ array(
+ 'base' => WC_LOG_DIR,
+ 'file' => 'index.html',
+ 'content' => '',
+ ),
+ array(
+ 'base' => $upload_dir['basedir'] . '/woocommerce_uploads',
+ 'file' => '.htaccess',
+ 'content' => 'redirect' === $download_method ? 'Options -Indexes' : 'deny from all',
+ ),
+ );
+
+ foreach ( $files as $file ) {
+ if ( wp_mkdir_p( $file['base'] ) && ! file_exists( trailingslashit( $file['base'] ) . $file['file'] ) ) {
+ $file_handle = @fopen( trailingslashit( $file['base'] ) . $file['file'], 'wb' ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged, WordPress.WP.AlternativeFunctions.file_system_read_fopen
+ if ( $file_handle ) {
+ fwrite( $file_handle, $file['content'] ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fwrite
+ fclose( $file_handle ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose
+ }
+ }
+ }
+
+ // Create attachment for placeholders.
+ self::create_placeholder_image();
+ }
+
+ /**
+ * Create a placeholder image in the media library.
+ *
+ * @since 3.5.0
+ */
+ private static function create_placeholder_image() {
+ $placeholder_image = get_option( 'woocommerce_placeholder_image', 0 );
+
+ // Validate current setting if set. If set, return.
+ if ( ! empty( $placeholder_image ) ) {
+ if ( ! is_numeric( $placeholder_image ) ) {
+ return;
+ } elseif ( $placeholder_image && wp_attachment_is_image( $placeholder_image ) ) {
+ return;
+ }
+ }
+
+ $upload_dir = wp_upload_dir();
+ $source = WC()->plugin_path() . '/assets/images/placeholder-attachment.png';
+ $filename = $upload_dir['basedir'] . '/woocommerce-placeholder.png';
+
+ if ( ! file_exists( $filename ) ) {
+ copy( $source, $filename ); // @codingStandardsIgnoreLine.
+ }
+
+ if ( ! file_exists( $filename ) ) {
+ update_option( 'woocommerce_placeholder_image', 0 );
+ return;
+ }
+
+ $filetype = wp_check_filetype( basename( $filename ), null );
+ $attachment = array(
+ 'guid' => $upload_dir['url'] . '/' . basename( $filename ),
+ 'post_mime_type' => $filetype['type'],
+ 'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $filename ) ),
+ 'post_content' => '',
+ 'post_status' => 'inherit',
+ );
+ $attach_id = wp_insert_attachment( $attachment, $filename );
+
+ update_option( 'woocommerce_placeholder_image', $attach_id );
+
+ // Make sure that this file is included, as wp_generate_attachment_metadata() depends on it.
+ require_once ABSPATH . 'wp-admin/includes/image.php';
+
+ // Generate the metadata for the attachment, and update the database record.
+ $attach_data = wp_generate_attachment_metadata( $attach_id, $filename );
+ wp_update_attachment_metadata( $attach_id, $attach_data );
+ }
+
+ /**
+ * Show action links on the plugin screen.
+ *
+ * @param mixed $links Plugin Action links.
+ *
+ * @return array
+ */
+ public static function plugin_action_links( $links ) {
+ $action_links = array(
+ 'settings' => '' . esc_html__( 'Settings', 'woocommerce' ) . '',
+ );
+
+ return array_merge( $action_links, $links );
+ }
+
+ /**
+ * Show row meta on the plugin screen.
+ *
+ * @param mixed $links Plugin Row Meta.
+ * @param mixed $file Plugin Base file.
+ *
+ * @return array
+ */
+ public static function plugin_row_meta( $links, $file ) {
+ if ( WC_PLUGIN_BASENAME !== $file ) {
+ return $links;
+ }
+
+ $row_meta = array(
+ 'docs' => '' . esc_html__( 'Docs', 'woocommerce' ) . '',
+ 'apidocs' => '' . esc_html__( 'API docs', 'woocommerce' ) . '',
+ 'support' => '' . esc_html__( 'Community support', 'woocommerce' ) . '',
+ );
+
+ if ( WCConnectionHelper::is_connected() ) {
+ $row_meta['premium_support'] = '' . esc_html__( 'Premium support', 'woocommerce' ) . '';
+ }
+
+ return array_merge( $links, $row_meta );
+ }
+
+ /**
+ * Get slug from path and associate it with the path.
+ *
+ * @param array $plugins Associative array of plugin files to paths.
+ * @param string $key Plugin relative path. Example: woocommerce/woocommerce.php.
+ */
+ private static function associate_plugin_file( $plugins, $key ) {
+ $path = explode( '/', $key );
+ $filename = end( $path );
+ $plugins[ $filename ] = $key;
+ return $plugins;
+ }
+
+ /**
+ * Install a plugin from .org in the background via a cron job (used by
+ * installer - opt in).
+ *
+ * @param string $plugin_to_install_id Plugin ID.
+ * @param array $plugin_to_install Plugin information.
+ *
+ * @throws Exception If unable to proceed with plugin installation.
+ * @since 2.6.0
+ */
+ public static function background_installer( $plugin_to_install_id, $plugin_to_install ) {
+ // Explicitly clear the event.
+ $args = func_get_args();
+
+ if ( ! empty( $plugin_to_install['repo-slug'] ) ) {
+ require_once ABSPATH . 'wp-admin/includes/file.php';
+ require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
+ require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
+ require_once ABSPATH . 'wp-admin/includes/plugin.php';
+
+ WP_Filesystem();
+
+ $skin = new Automatic_Upgrader_Skin();
+ $upgrader = new WP_Upgrader( $skin );
+ $installed_plugins = array_reduce( array_keys( get_plugins() ), array( __CLASS__, 'associate_plugin_file' ) );
+ if ( empty( $installed_plugins ) ) {
+ $installed_plugins = array();
+ }
+ $plugin_slug = $plugin_to_install['repo-slug'];
+ $plugin_file = isset( $plugin_to_install['file'] ) ? $plugin_to_install['file'] : $plugin_slug . '.php';
+ $installed = false;
+ $activate = false;
+
+ // See if the plugin is installed already.
+ if ( isset( $installed_plugins[ $plugin_file ] ) ) {
+ $installed = true;
+ $activate = ! is_plugin_active( $installed_plugins[ $plugin_file ] );
+ }
+
+ // Install this thing!
+ if ( ! $installed ) {
+ // Suppress feedback.
+ ob_start();
+
+ try {
+ $plugin_information = plugins_api(
+ 'plugin_information',
+ array(
+ 'slug' => $plugin_slug,
+ 'fields' => array(
+ 'short_description' => false,
+ 'sections' => false,
+ 'requires' => false,
+ 'rating' => false,
+ 'ratings' => false,
+ 'downloaded' => false,
+ 'last_updated' => false,
+ 'added' => false,
+ 'tags' => false,
+ 'homepage' => false,
+ 'donate_link' => false,
+ 'author_profile' => false,
+ 'author' => false,
+ ),
+ )
+ );
+
+ if ( is_wp_error( $plugin_information ) ) {
+ throw new Exception( $plugin_information->get_error_message() );
+ }
+
+ $package = $plugin_information->download_link;
+ $download = $upgrader->download_package( $package );
+
+ if ( is_wp_error( $download ) ) {
+ throw new Exception( $download->get_error_message() );
+ }
+
+ $working_dir = $upgrader->unpack_package( $download, true );
+
+ if ( is_wp_error( $working_dir ) ) {
+ throw new Exception( $working_dir->get_error_message() );
+ }
+
+ $result = $upgrader->install_package(
+ array(
+ 'source' => $working_dir,
+ 'destination' => WP_PLUGIN_DIR,
+ 'clear_destination' => false,
+ 'abort_if_destination_exists' => false,
+ 'clear_working' => true,
+ 'hook_extra' => array(
+ 'type' => 'plugin',
+ 'action' => 'install',
+ ),
+ )
+ );
+
+ if ( is_wp_error( $result ) ) {
+ throw new Exception( $result->get_error_message() );
+ }
+
+ $activate = true;
+
+ } catch ( Exception $e ) {
+ WC_Admin_Notices::add_custom_notice(
+ $plugin_to_install_id . '_install_error',
+ sprintf(
+ // translators: 1: plugin name, 2: error message, 3: URL to install plugin manually.
+ __( '%1$s could not be installed (%2$s). Please install it manually by clicking here.', 'woocommerce' ),
+ $plugin_to_install['name'],
+ $e->getMessage(),
+ esc_url( admin_url( 'index.php?wc-install-plugin-redirect=' . $plugin_slug ) )
+ )
+ );
+ }
+
+ // Discard feedback.
+ ob_end_clean();
+ }
+
+ wp_clean_plugins_cache();
+
+ // Activate this thing.
+ if ( $activate ) {
+ try {
+ add_action( 'add_option_mailchimp_woocommerce_plugin_do_activation_redirect', array( __CLASS__, 'remove_mailchimps_redirect' ), 10, 2 );
+ $result = activate_plugin( $installed ? $installed_plugins[ $plugin_file ] : $plugin_slug . '/' . $plugin_file );
+
+ if ( is_wp_error( $result ) ) {
+ throw new Exception( $result->get_error_message() );
+ }
+ } catch ( Exception $e ) {
+ WC_Admin_Notices::add_custom_notice(
+ $plugin_to_install_id . '_install_error',
+ sprintf(
+ // translators: 1: plugin name, 2: URL to WP plugin page.
+ __( '%1$s was installed but could not be activated. Please activate it manually by clicking here.', 'woocommerce' ),
+ $plugin_to_install['name'],
+ admin_url( 'plugins.php' )
+ )
+ );
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes redirect added during MailChimp plugin's activation.
+ *
+ * @param string $option Option name.
+ * @param string $value Option value.
+ */
+ public static function remove_mailchimps_redirect( $option, $value ) {
+ // Remove this action to prevent infinite looping.
+ remove_action( 'add_option_mailchimp_woocommerce_plugin_do_activation_redirect', array( __CLASS__, 'remove_mailchimps_redirect' ) );
+
+ // Update redirect back to false.
+ update_option( 'mailchimp_woocommerce_plugin_do_activation_redirect', false );
+ }
+
+ /**
+ * Install a theme from .org in the background via a cron job (used by installer - opt in).
+ *
+ * @param string $theme_slug Theme slug.
+ *
+ * @throws Exception If unable to proceed with theme installation.
+ * @since 3.1.0
+ */
+ public static function theme_background_installer( $theme_slug ) {
+ // Explicitly clear the event.
+ $args = func_get_args();
+
+ if ( ! empty( $theme_slug ) ) {
+ // Suppress feedback.
+ ob_start();
+
+ try {
+ $theme = wp_get_theme( $theme_slug );
+
+ if ( ! $theme->exists() ) {
+ require_once ABSPATH . 'wp-admin/includes/file.php';
+ include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
+ include_once ABSPATH . 'wp-admin/includes/theme.php';
+
+ WP_Filesystem();
+
+ $skin = new Automatic_Upgrader_Skin();
+ $upgrader = new Theme_Upgrader( $skin );
+ $api = themes_api(
+ 'theme_information',
+ array(
+ 'slug' => $theme_slug,
+ 'fields' => array( 'sections' => false ),
+ )
+ );
+ $result = $upgrader->install( $api->download_link );
+
+ if ( is_wp_error( $result ) ) {
+ throw new Exception( $result->get_error_message() );
+ } elseif ( is_wp_error( $skin->result ) ) {
+ throw new Exception( $skin->result->get_error_message() );
+ } elseif ( is_null( $result ) ) {
+ throw new Exception( 'Unable to connect to the filesystem. Please confirm your credentials.' );
+ }
+ }
+
+ switch_theme( $theme_slug );
+ } catch ( Exception $e ) {
+ WC_Admin_Notices::add_custom_notice(
+ $theme_slug . '_install_error',
+ sprintf(
+ // translators: 1: theme slug, 2: error message, 3: URL to install theme manually.
+ __( '%1$s could not be installed (%2$s). Please install it manually by clicking here.', 'woocommerce' ),
+ $theme_slug,
+ $e->getMessage(),
+ esc_url( admin_url( 'update.php?action=install-theme&theme=' . $theme_slug . '&_wpnonce=' . wp_create_nonce( 'install-theme_' . $theme_slug ) ) )
+ )
+ );
+ }
+
+ // Discard feedback.
+ ob_end_clean();
+ }
+ }
+}
+
+WC_Install::init();
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-integrations.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-integrations.php
new file mode 100644
index 0000000..f29360b
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-integrations.php
@@ -0,0 +1,70 @@
+integrations[ $load_integration->id ] = $load_integration;
+ }
+ }
+
+ /**
+ * Return loaded integrations.
+ *
+ * @return array
+ */
+ public function get_integrations() {
+ return $this->integrations;
+ }
+
+ /**
+ * Return a desired integration.
+ *
+ * @since 3.9.0
+ * @param string $id The id of the integration to get.
+ * @return mixed|null The integration if one is found, otherwise null.
+ */
+ public function get_integration( $id ) {
+ if ( isset( $this->integrations[ $id ] ) ) {
+ return $this->integrations[ $id ];
+ }
+
+ return null;
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-log-levels.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-log-levels.php
new file mode 100644
index 0000000..f577b55
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-log-levels.php
@@ -0,0 +1,108 @@
+ 800,
+ self::ALERT => 700,
+ self::CRITICAL => 600,
+ self::ERROR => 500,
+ self::WARNING => 400,
+ self::NOTICE => 300,
+ self::INFO => 200,
+ self::DEBUG => 100,
+ );
+
+ /**
+ * Severity integers mapped to level strings.
+ *
+ * This is the inverse of $level_severity.
+ *
+ * @var array
+ */
+ protected static $severity_to_level = array(
+ 800 => self::EMERGENCY,
+ 700 => self::ALERT,
+ 600 => self::CRITICAL,
+ 500 => self::ERROR,
+ 400 => self::WARNING,
+ 300 => self::NOTICE,
+ 200 => self::INFO,
+ 100 => self::DEBUG,
+ );
+
+
+ /**
+ * Validate a level string.
+ *
+ * @param string $level Log level.
+ * @return bool True if $level is a valid level.
+ */
+ public static function is_valid_level( $level ) {
+ return array_key_exists( strtolower( $level ), self::$level_to_severity );
+ }
+
+ /**
+ * Translate level string to integer.
+ *
+ * @param string $level Log level, options: emergency|alert|critical|error|warning|notice|info|debug.
+ * @return int 100 (debug) - 800 (emergency) or 0 if not recognized
+ */
+ public static function get_level_severity( $level ) {
+ return self::is_valid_level( $level ) ? self::$level_to_severity[ strtolower( $level ) ] : 0;
+ }
+
+ /**
+ * Translate severity integer to level string.
+ *
+ * @param int $severity Severity level.
+ * @return bool|string False if not recognized. Otherwise string representation of level.
+ */
+ public static function get_severity_level( $severity ) {
+ if ( ! array_key_exists( $severity, self::$severity_to_level ) ) {
+ return false;
+ }
+ return self::$severity_to_level[ $severity ];
+ }
+
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-logger.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-logger.php
new file mode 100644
index 0000000..040dd58
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-logger.php
@@ -0,0 +1,303 @@
+' . esc_html( is_object( $handler ) ? get_class( $handler ) : $handler ) . '',
+ 'WC_Log_Handler_Interface
'
+ ),
+ '3.0'
+ );
+ }
+ }
+ }
+
+ // Support the constant as long as a valid log level has been set for it.
+ if ( null === $threshold ) {
+ $threshold = Constants::get_constant( 'WC_LOG_THRESHOLD' );
+ if ( null !== $threshold && ! WC_Log_Levels::is_valid_level( $threshold ) ) {
+ $threshold = null;
+ }
+ }
+
+ if ( null !== $threshold ) {
+ $threshold = WC_Log_Levels::get_level_severity( $threshold );
+ }
+
+ $this->handlers = $register_handlers;
+ $this->threshold = $threshold;
+ }
+
+ /**
+ * Determine whether to handle or ignore log.
+ *
+ * @param string $level emergency|alert|critical|error|warning|notice|info|debug.
+ * @return bool True if the log should be handled.
+ */
+ protected function should_handle( $level ) {
+ if ( null === $this->threshold ) {
+ return true;
+ }
+ return $this->threshold <= WC_Log_Levels::get_level_severity( $level );
+ }
+
+ /**
+ * Add a log entry.
+ *
+ * This is not the preferred method for adding log messages. Please use log() or any one of
+ * the level methods (debug(), info(), etc.). This method may be deprecated in the future.
+ *
+ * @param string $handle File handle.
+ * @param string $message Message to log.
+ * @param string $level Logging level.
+ * @return bool
+ */
+ public function add( $handle, $message, $level = WC_Log_Levels::NOTICE ) {
+ $message = apply_filters( 'woocommerce_logger_add_message', $message, $handle );
+ $this->log(
+ $level,
+ $message,
+ array(
+ 'source' => $handle,
+ '_legacy' => true,
+ )
+ );
+ wc_do_deprecated_action( 'woocommerce_log_add', array( $handle, $message ), '3.0', 'This action has been deprecated with no alternative.' );
+ return true;
+ }
+
+ /**
+ * Add a log entry.
+ *
+ * @param string $level One of the following:
+ * 'emergency': System is unusable.
+ * 'alert': Action must be taken immediately.
+ * 'critical': Critical conditions.
+ * 'error': Error conditions.
+ * 'warning': Warning conditions.
+ * 'notice': Normal but significant condition.
+ * 'info': Informational messages.
+ * 'debug': Debug-level messages.
+ * @param string $message Log message.
+ * @param array $context Optional. Additional information for log handlers.
+ */
+ public function log( $level, $message, $context = array() ) {
+ if ( ! WC_Log_Levels::is_valid_level( $level ) ) {
+ /* translators: 1: WC_Logger::log 2: level */
+ wc_doing_it_wrong( __METHOD__, sprintf( __( '%1$s was called with an invalid level "%2$s".', 'woocommerce' ), 'WC_Logger::log
', $level ), '3.0' );
+ }
+
+ if ( $this->should_handle( $level ) ) {
+ $timestamp = current_time( 'timestamp', 1 );
+ $message = apply_filters( 'woocommerce_logger_log_message', $message, $level, $context );
+
+ foreach ( $this->handlers as $handler ) {
+ $handler->handle( $timestamp, $level, $message, $context );
+ }
+ }
+ }
+
+ /**
+ * Adds an emergency level message.
+ *
+ * System is unusable.
+ *
+ * @see WC_Logger::log
+ *
+ * @param string $message Message to log.
+ * @param array $context Log context.
+ */
+ public function emergency( $message, $context = array() ) {
+ $this->log( WC_Log_Levels::EMERGENCY, $message, $context );
+ }
+
+ /**
+ * Adds an alert level message.
+ *
+ * Action must be taken immediately.
+ * Example: Entire website down, database unavailable, etc.
+ *
+ * @see WC_Logger::log
+ *
+ * @param string $message Message to log.
+ * @param array $context Log context.
+ */
+ public function alert( $message, $context = array() ) {
+ $this->log( WC_Log_Levels::ALERT, $message, $context );
+ }
+
+ /**
+ * Adds a critical level message.
+ *
+ * Critical conditions.
+ * Example: Application component unavailable, unexpected exception.
+ *
+ * @see WC_Logger::log
+ *
+ * @param string $message Message to log.
+ * @param array $context Log context.
+ */
+ public function critical( $message, $context = array() ) {
+ $this->log( WC_Log_Levels::CRITICAL, $message, $context );
+ }
+
+ /**
+ * Adds an error level message.
+ *
+ * Runtime errors that do not require immediate action but should typically be logged
+ * and monitored.
+ *
+ * @see WC_Logger::log
+ *
+ * @param string $message Message to log.
+ * @param array $context Log context.
+ */
+ public function error( $message, $context = array() ) {
+ $this->log( WC_Log_Levels::ERROR, $message, $context );
+ }
+
+ /**
+ * Adds a warning level message.
+ *
+ * Exceptional occurrences that are not errors.
+ *
+ * Example: Use of deprecated APIs, poor use of an API, undesirable things that are not
+ * necessarily wrong.
+ *
+ * @see WC_Logger::log
+ *
+ * @param string $message Message to log.
+ * @param array $context Log context.
+ */
+ public function warning( $message, $context = array() ) {
+ $this->log( WC_Log_Levels::WARNING, $message, $context );
+ }
+
+ /**
+ * Adds a notice level message.
+ *
+ * Normal but significant events.
+ *
+ * @see WC_Logger::log
+ *
+ * @param string $message Message to log.
+ * @param array $context Log context.
+ */
+ public function notice( $message, $context = array() ) {
+ $this->log( WC_Log_Levels::NOTICE, $message, $context );
+ }
+
+ /**
+ * Adds a info level message.
+ *
+ * Interesting events.
+ * Example: User logs in, SQL logs.
+ *
+ * @see WC_Logger::log
+ *
+ * @param string $message Message to log.
+ * @param array $context Log context.
+ */
+ public function info( $message, $context = array() ) {
+ $this->log( WC_Log_Levels::INFO, $message, $context );
+ }
+
+ /**
+ * Adds a debug level message.
+ *
+ * Detailed debug information.
+ *
+ * @see WC_Logger::log
+ *
+ * @param string $message Message to log.
+ * @param array $context Log context.
+ */
+ public function debug( $message, $context = array() ) {
+ $this->log( WC_Log_Levels::DEBUG, $message, $context );
+ }
+
+ /**
+ * Clear entries for a chosen file/source.
+ *
+ * @param string $source Source/handle to clear.
+ * @return bool
+ */
+ public function clear( $source = '' ) {
+ if ( ! $source ) {
+ return false;
+ }
+ foreach ( $this->handlers as $handler ) {
+ if ( is_callable( array( $handler, 'clear' ) ) ) {
+ $handler->clear( $source );
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Clear all logs older than a defined number of days. Defaults to 30 days.
+ *
+ * @since 3.4.0
+ */
+ public function clear_expired_logs() {
+ $days = absint( apply_filters( 'woocommerce_logger_days_to_retain_logs', 30 ) );
+ $timestamp = strtotime( "-{$days} days" );
+
+ foreach ( $this->handlers as $handler ) {
+ if ( is_callable( array( $handler, 'delete_logs_before_timestamp' ) ) ) {
+ $handler->delete_logs_before_timestamp( $timestamp );
+ }
+ }
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-meta-data.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-meta-data.php
new file mode 100644
index 0000000..c21d98d
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-meta-data.php
@@ -0,0 +1,119 @@
+current_data = $meta;
+ $this->apply_changes();
+ }
+
+ /**
+ * When converted to JSON.
+ *
+ * @return object|array
+ */
+ public function jsonSerialize() {
+ return $this->get_data();
+ }
+
+ /**
+ * Merge changes with data and clear.
+ */
+ public function apply_changes() {
+ $this->data = $this->current_data;
+ }
+
+ /**
+ * Creates or updates a property in the metadata object.
+ *
+ * @param string $key Key to set.
+ * @param mixed $value Value to set.
+ */
+ public function __set( $key, $value ) {
+ $this->current_data[ $key ] = $value;
+ }
+
+ /**
+ * Checks if a given key exists in our data. This is called internally
+ * by `empty` and `isset`.
+ *
+ * @param string $key Key to check if set.
+ *
+ * @return bool
+ */
+ public function __isset( $key ) {
+ return array_key_exists( $key, $this->current_data );
+ }
+
+ /**
+ * Returns the value of any property.
+ *
+ * @param string $key Key to get.
+ * @return mixed Property value or NULL if it does not exists
+ */
+ public function __get( $key ) {
+ if ( array_key_exists( $key, $this->current_data ) ) {
+ return $this->current_data[ $key ];
+ }
+ return null;
+ }
+
+ /**
+ * Return data changes only.
+ *
+ * @return array
+ */
+ public function get_changes() {
+ $changes = array();
+ foreach ( $this->current_data as $id => $value ) {
+ if ( ! array_key_exists( $id, $this->data ) || $value !== $this->data[ $id ] ) {
+ $changes[ $id ] = $value;
+ }
+ }
+ return $changes;
+ }
+
+ /**
+ * Return all data as an array.
+ *
+ * @return array
+ */
+ public function get_data() {
+ return $this->data;
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-factory.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-factory.php
new file mode 100644
index 0000000..a307787
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-factory.php
@@ -0,0 +1,131 @@
+get_order_type( $order_id );
+ $order_type_data = wc_get_order_type( $order_type );
+ if ( $order_type_data ) {
+ $classname = $order_type_data['class_name'];
+ } else {
+ $classname = false;
+ }
+
+ // Filter classname so that the class can be overridden if extended.
+ $classname = apply_filters( 'woocommerce_order_class', $classname, $order_type, $order_id );
+
+ if ( ! class_exists( $classname ) ) {
+ return false;
+ }
+
+ try {
+ return new $classname( $order_id );
+ } catch ( Exception $e ) {
+ wc_caught_exception( $e, __FUNCTION__, array( $order_id ) );
+ return false;
+ }
+ }
+
+ /**
+ * Get order item.
+ *
+ * @param int $item_id Order item ID to get.
+ * @return WC_Order_Item|false if not found
+ */
+ public static function get_order_item( $item_id = 0 ) {
+ if ( is_numeric( $item_id ) ) {
+ $item_type = WC_Data_Store::load( 'order-item' )->get_order_item_type( $item_id );
+ $id = $item_id;
+ } elseif ( $item_id instanceof WC_Order_Item ) {
+ $item_type = $item_id->get_type();
+ $id = $item_id->get_id();
+ } elseif ( is_object( $item_id ) && ! empty( $item_id->order_item_type ) ) {
+ $id = $item_id->order_item_id;
+ $item_type = $item_id->order_item_type;
+ } else {
+ $item_type = false;
+ $id = false;
+ }
+
+ if ( $id && $item_type ) {
+ $classname = false;
+ switch ( $item_type ) {
+ case 'line_item':
+ case 'product':
+ $classname = 'WC_Order_Item_Product';
+ break;
+ case 'coupon':
+ $classname = 'WC_Order_Item_Coupon';
+ break;
+ case 'fee':
+ $classname = 'WC_Order_Item_Fee';
+ break;
+ case 'shipping':
+ $classname = 'WC_Order_Item_Shipping';
+ break;
+ case 'tax':
+ $classname = 'WC_Order_Item_Tax';
+ break;
+ }
+
+ $classname = apply_filters( 'woocommerce_get_order_item_classname', $classname, $item_type, $id );
+
+ if ( $classname && class_exists( $classname ) ) {
+ try {
+ return new $classname( $id );
+ } catch ( Exception $e ) {
+ return false;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get the order ID depending on what was passed.
+ *
+ * @since 3.0.0
+ * @param mixed $order Order data to convert to an ID.
+ * @return int|bool false on failure
+ */
+ public static function get_order_id( $order ) {
+ global $post;
+
+ if ( false === $order && is_a( $post, 'WP_Post' ) && 'shop_order' === get_post_type( $post ) ) {
+ return absint( $post->ID );
+ } elseif ( is_numeric( $order ) ) {
+ return $order;
+ } elseif ( $order instanceof WC_Abstract_Order ) {
+ return $order->get_id();
+ } elseif ( ! empty( $order->ID ) ) {
+ return $order->ID;
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-item-coupon.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-item-coupon.php
new file mode 100644
index 0000000..1a8aa50
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-item-coupon.php
@@ -0,0 +1,182 @@
+ '',
+ 'discount' => 0,
+ 'discount_tax' => 0,
+ );
+
+ /*
+ |--------------------------------------------------------------------------
+ | Setters
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Set order item name.
+ *
+ * @param string $value Coupon code.
+ */
+ public function set_name( $value ) {
+ return $this->set_code( $value );
+ }
+
+ /**
+ * Set code.
+ *
+ * @param string $value Coupon code.
+ */
+ public function set_code( $value ) {
+ $this->set_prop( 'code', wc_format_coupon_code( $value ) );
+ }
+
+ /**
+ * Set discount amount.
+ *
+ * @param string $value Discount.
+ */
+ public function set_discount( $value ) {
+ $this->set_prop( 'discount', wc_format_decimal( $value ) );
+ }
+
+ /**
+ * Set discounted tax amount.
+ *
+ * @param string $value Discount tax.
+ */
+ public function set_discount_tax( $value ) {
+ $this->set_prop( 'discount_tax', wc_format_decimal( $value ) );
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Getters
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Get order item type.
+ *
+ * @return string
+ */
+ public function get_type() {
+ return 'coupon';
+ }
+
+ /**
+ * Get order item name.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_name( $context = 'view' ) {
+ return $this->get_code( $context );
+ }
+
+ /**
+ * Get coupon code.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_code( $context = 'view' ) {
+ return $this->get_prop( 'code', $context );
+ }
+
+ /**
+ * Get discount amount.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_discount( $context = 'view' ) {
+ return $this->get_prop( 'discount', $context );
+ }
+
+ /**
+ * Get discounted tax amount.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ *
+ * @return string
+ */
+ public function get_discount_tax( $context = 'view' ) {
+ return $this->get_prop( 'discount_tax', $context );
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Array Access Methods
+ |--------------------------------------------------------------------------
+ |
+ | For backwards compatibility with legacy arrays.
+ |
+ */
+
+ /**
+ * OffsetGet for ArrayAccess/Backwards compatibility.
+ *
+ * @deprecated 4.4.0
+ * @param string $offset Offset.
+ * @return mixed
+ */
+ public function offsetGet( $offset ) {
+ wc_deprecated_function( 'WC_Order_Item_Coupon::offsetGet', '4.4.0', '' );
+ if ( 'discount_amount' === $offset ) {
+ $offset = 'discount';
+ } elseif ( 'discount_amount_tax' === $offset ) {
+ $offset = 'discount_tax';
+ }
+ return parent::offsetGet( $offset );
+ }
+
+ /**
+ * OffsetSet for ArrayAccess/Backwards compatibility.
+ *
+ * @deprecated 4.4.0
+ * @param string $offset Offset.
+ * @param mixed $value Value.
+ */
+ public function offsetSet( $offset, $value ) {
+ wc_deprecated_function( 'WC_Order_Item_Coupon::offsetSet', '4.4.0', '' );
+ if ( 'discount_amount' === $offset ) {
+ $offset = 'discount';
+ } elseif ( 'discount_amount_tax' === $offset ) {
+ $offset = 'discount_tax';
+ }
+ parent::offsetSet( $offset, $value );
+ }
+
+ /**
+ * OffsetExists for ArrayAccess.
+ *
+ * @param string $offset Offset.
+ * @return bool
+ */
+ public function offsetExists( $offset ) {
+ if ( in_array( $offset, array( 'discount_amount', 'discount_amount_tax' ), true ) ) {
+ return true;
+ }
+ return parent::offsetExists( $offset );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-item-fee.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-item-fee.php
new file mode 100644
index 0000000..44e1ee1
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-item-fee.php
@@ -0,0 +1,338 @@
+ '',
+ 'tax_status' => 'taxable',
+ 'amount' => '',
+ 'total' => '',
+ 'total_tax' => '',
+ 'taxes' => array(
+ 'total' => array(),
+ ),
+ );
+
+ /**
+ * Get item costs grouped by tax class.
+ *
+ * @since 3.2.0
+ * @param WC_Order $order Order object.
+ * @return array
+ */
+ protected function get_tax_class_costs( $order ) {
+ $order_item_tax_classes = $order->get_items_tax_classes();
+ $costs = array_fill_keys( $order_item_tax_classes, 0 );
+ $costs['non-taxable'] = 0;
+
+ foreach ( $order->get_items( array( 'line_item', 'fee', 'shipping' ) ) as $item ) {
+ if ( 0 > $item->get_total() ) {
+ continue;
+ }
+ if ( 'taxable' !== $item->get_tax_status() ) {
+ $costs['non-taxable'] += $item->get_total();
+ } elseif ( 'inherit' === $item->get_tax_class() ) {
+ $inherit_class = reset( $order_item_tax_classes );
+ $costs[ $inherit_class ] += $item->get_total();
+ } else {
+ $costs[ $item->get_tax_class() ] += $item->get_total();
+ }
+ }
+
+ return array_filter( $costs );
+ }
+ /**
+ * Calculate item taxes.
+ *
+ * @since 3.2.0
+ * @param array $calculate_tax_for Location data to get taxes for. Required.
+ * @return bool True if taxes were calculated.
+ */
+ public function calculate_taxes( $calculate_tax_for = array() ) {
+ if ( ! isset( $calculate_tax_for['country'], $calculate_tax_for['state'], $calculate_tax_for['postcode'], $calculate_tax_for['city'] ) ) {
+ return false;
+ }
+ // Use regular calculation unless the fee is negative.
+ if ( 0 <= $this->get_total() ) {
+ return parent::calculate_taxes( $calculate_tax_for );
+ }
+
+ if ( wc_tax_enabled() && $this->get_order() ) {
+ // Apportion taxes to order items, shipping, and fees.
+ $order = $this->get_order();
+ $tax_class_costs = $this->get_tax_class_costs( $order );
+ $total_costs = array_sum( $tax_class_costs );
+ $discount_taxes = array();
+ if ( $total_costs ) {
+ foreach ( $tax_class_costs as $tax_class => $tax_class_cost ) {
+ if ( 'non-taxable' === $tax_class ) {
+ continue;
+ }
+ $proportion = $tax_class_cost / $total_costs;
+ $cart_discount_proportion = $this->get_total() * $proportion;
+ $calculate_tax_for['tax_class'] = $tax_class;
+ $tax_rates = WC_Tax::find_rates( $calculate_tax_for );
+ $discount_taxes = wc_array_merge_recursive_numeric( $discount_taxes, WC_Tax::calc_tax( $cart_discount_proportion, $tax_rates ) );
+ }
+ }
+ $this->set_taxes( array( 'total' => $discount_taxes ) );
+ } else {
+ $this->set_taxes( false );
+ }
+
+ do_action( 'woocommerce_order_item_fee_after_calculate_taxes', $this, $calculate_tax_for );
+
+ return true;
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Setters
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Set fee amount.
+ *
+ * @param string $value Amount.
+ */
+ public function set_amount( $value ) {
+ $this->set_prop( 'amount', wc_format_decimal( $value ) );
+ }
+
+ /**
+ * Set tax class.
+ *
+ * @param string $value Tax class.
+ */
+ public function set_tax_class( $value ) {
+ if ( $value && ! in_array( $value, WC_Tax::get_tax_class_slugs(), true ) ) {
+ $this->error( 'order_item_fee_invalid_tax_class', __( 'Invalid tax class', 'woocommerce' ) );
+ }
+ $this->set_prop( 'tax_class', $value );
+ }
+
+ /**
+ * Set tax_status.
+ *
+ * @param string $value Tax status.
+ */
+ public function set_tax_status( $value ) {
+ if ( in_array( $value, array( 'taxable', 'none' ), true ) ) {
+ $this->set_prop( 'tax_status', $value );
+ } else {
+ $this->set_prop( 'tax_status', 'taxable' );
+ }
+ }
+
+ /**
+ * Set total.
+ *
+ * @param string $amount Fee amount (do not enter negative amounts).
+ */
+ public function set_total( $amount ) {
+ $this->set_prop( 'total', wc_format_decimal( $amount ) );
+ }
+
+ /**
+ * Set total tax.
+ *
+ * @param string $amount Amount.
+ */
+ public function set_total_tax( $amount ) {
+ $this->set_prop( 'total_tax', wc_format_decimal( $amount ) );
+ }
+
+ /**
+ * Set taxes.
+ *
+ * This is an array of tax ID keys with total amount values.
+ *
+ * @param array $raw_tax_data Raw tax data.
+ */
+ public function set_taxes( $raw_tax_data ) {
+ $raw_tax_data = maybe_unserialize( $raw_tax_data );
+ $tax_data = array(
+ 'total' => array(),
+ );
+ if ( ! empty( $raw_tax_data['total'] ) ) {
+ $tax_data['total'] = array_map( 'wc_format_decimal', $raw_tax_data['total'] );
+ }
+ $this->set_prop( 'taxes', $tax_data );
+
+ if ( 'yes' === get_option( 'woocommerce_tax_round_at_subtotal' ) ) {
+ $this->set_total_tax( array_sum( $tax_data['total'] ) );
+ } else {
+ $this->set_total_tax( array_sum( array_map( 'wc_round_tax_total', $tax_data['total'] ) ) );
+ }
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Getters
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Get fee amount.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_amount( $context = 'view' ) {
+ return $this->get_prop( 'amount', $context );
+ }
+
+ /**
+ * Get order item name.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_name( $context = 'view' ) {
+ $name = $this->get_prop( 'name', $context );
+ if ( 'view' === $context ) {
+ return $name ? $name : __( 'Fee', 'woocommerce' );
+ } else {
+ return $name;
+ }
+ }
+
+ /**
+ * Get order item type.
+ *
+ * @return string
+ */
+ public function get_type() {
+ return 'fee';
+ }
+
+ /**
+ * Get tax class.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_tax_class( $context = 'view' ) {
+ return $this->get_prop( 'tax_class', $context );
+ }
+
+ /**
+ * Get tax status.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_tax_status( $context = 'view' ) {
+ return $this->get_prop( 'tax_status', $context );
+ }
+
+ /**
+ * Get total fee.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_total( $context = 'view' ) {
+ return $this->get_prop( 'total', $context );
+ }
+
+ /**
+ * Get total tax.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_total_tax( $context = 'view' ) {
+ return $this->get_prop( 'total_tax', $context );
+ }
+
+ /**
+ * Get fee taxes.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return array
+ */
+ public function get_taxes( $context = 'view' ) {
+ return $this->get_prop( 'taxes', $context );
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Array Access Methods
+ |--------------------------------------------------------------------------
+ |
+ | For backwards compatibility with legacy arrays.
+ |
+ */
+
+ /**
+ * OffsetGet for ArrayAccess/Backwards compatibility.
+ *
+ * @param string $offset Offset.
+ * @return mixed
+ */
+ public function offsetGet( $offset ) {
+ if ( 'line_total' === $offset ) {
+ $offset = 'total';
+ } elseif ( 'line_tax' === $offset ) {
+ $offset = 'total_tax';
+ } elseif ( 'line_tax_data' === $offset ) {
+ $offset = 'taxes';
+ }
+ return parent::offsetGet( $offset );
+ }
+
+ /**
+ * OffsetSet for ArrayAccess/Backwards compatibility.
+ *
+ * @deprecated 4.4.0
+ * @param string $offset Offset.
+ * @param mixed $value Value.
+ */
+ public function offsetSet( $offset, $value ) {
+ wc_deprecated_function( 'WC_Order_Item_Fee::offsetSet', '4.4.0', '' );
+ if ( 'line_total' === $offset ) {
+ $offset = 'total';
+ } elseif ( 'line_tax' === $offset ) {
+ $offset = 'total_tax';
+ } elseif ( 'line_tax_data' === $offset ) {
+ $offset = 'taxes';
+ }
+ parent::offsetSet( $offset, $value );
+ }
+
+ /**
+ * OffsetExists for ArrayAccess
+ *
+ * @param string $offset Offset.
+ * @return bool
+ */
+ public function offsetExists( $offset ) {
+ if ( in_array( $offset, array( 'line_total', 'line_tax', 'line_tax_data' ), true ) ) {
+ return true;
+ }
+ return parent::offsetExists( $offset );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-item-meta.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-item-meta.php
new file mode 100644
index 0000000..693be23
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-item-meta.php
@@ -0,0 +1,215 @@
+legacy = true;
+ $this->meta = array_filter( (array) $item );
+ return;
+ }
+ $this->item = $item;
+ $this->meta = array_filter( (array) $item['item_meta'] );
+ $this->product = $product;
+ }
+
+ /**
+ * Display meta in a formatted list.
+ *
+ * @param bool $flat Flat (default: false).
+ * @param bool $return Return (default: false).
+ * @param string $hideprefix Hide prefix (default: _).
+ * @param string $delimiter Delimiter used to separate items when $flat is true.
+ * @return string|void
+ */
+ public function display( $flat = false, $return = false, $hideprefix = '_', $delimiter = ", \n" ) {
+ $output = '';
+ $formatted_meta = $this->get_formatted( $hideprefix );
+
+ if ( ! empty( $formatted_meta ) ) {
+ $meta_list = array();
+
+ foreach ( $formatted_meta as $meta ) {
+ if ( $flat ) {
+ $meta_list[] = wp_kses_post( $meta['label'] . ': ' . $meta['value'] );
+ } else {
+ $meta_list[] = '
+
+
+ '; + } + } + + if ( ! empty( $meta_list ) ) { + if ( $flat ) { + $output .= implode( $delimiter, $meta_list ); + } else { + $output .= '
';
+ }
+ }
+ }
+
+ $output = apply_filters( 'woocommerce_order_items_meta_display', $output, $this, $flat );
+
+ if ( $return ) {
+ return $output;
+ } else {
+ echo $output; // WPCS: XSS ok.
+ }
+ }
+
+ /**
+ * Return an array of formatted item meta in format e.g.
+ *
+ * Returns: array(
+ * 'pa_size' => array(
+ * 'label' => 'Size',
+ * 'value' => 'Medium',
+ * )
+ * )
+ *
+ * @since 2.4
+ * @param string $hideprefix exclude meta when key is prefixed with this, defaults to '_'.
+ * @return array
+ */
+ public function get_formatted( $hideprefix = '_' ) {
+ if ( $this->legacy ) {
+ return $this->get_formatted_legacy( $hideprefix );
+ }
+
+ $formatted_meta = array();
+
+ if ( ! empty( $this->item['item_meta_array'] ) ) {
+ foreach ( $this->item['item_meta_array'] as $meta_id => $meta ) {
+ if ( '' === $meta->value || is_serialized( $meta->value ) || ( ! empty( $hideprefix ) && substr( $meta->key, 0, 1 ) === $hideprefix ) ) {
+ continue;
+ }
+
+ $attribute_key = urldecode( str_replace( 'attribute_', '', $meta->key ) );
+ $meta_value = $meta->value;
+
+ // If this is a term slug, get the term's nice name.
+ if ( taxonomy_exists( $attribute_key ) ) {
+ $term = get_term_by( 'slug', $meta_value, $attribute_key );
+
+ if ( ! is_wp_error( $term ) && is_object( $term ) && $term->name ) {
+ $meta_value = $term->name;
+ }
+ }
+
+ $formatted_meta[ $meta_id ] = array(
+ 'key' => $meta->key,
+ 'label' => wc_attribute_label( $attribute_key, $this->product ),
+ 'value' => apply_filters( 'woocommerce_order_item_display_meta_value', $meta_value, $meta, $this->item ),
+ );
+ }
+ }
+
+ return apply_filters( 'woocommerce_order_items_meta_get_formatted', $formatted_meta, $this );
+ }
+
+ /**
+ * Return an array of formatted item meta in format e.g.
+ * Handles @deprecated args.
+ *
+ * @param string $hideprefix Hide prefix.
+ *
+ * @return array
+ */
+ public function get_formatted_legacy( $hideprefix = '_' ) {
+ if ( ! is_ajax() ) {
+ wc_deprecated_argument( 'WC_Order_Item_Meta::get_formatted', '2.4', 'Item Meta Data is being called with legacy arguments' );
+ }
+
+ $formatted_meta = array();
+
+ foreach ( $this->meta as $meta_key => $meta_values ) {
+ if ( empty( $meta_values ) || ( ! empty( $hideprefix ) && substr( $meta_key, 0, 1 ) === $hideprefix ) ) {
+ continue;
+ }
+ foreach ( (array) $meta_values as $meta_value ) {
+ // Skip serialised meta.
+ if ( is_serialized( $meta_value ) ) {
+ continue;
+ }
+
+ $attribute_key = urldecode( str_replace( 'attribute_', '', $meta_key ) );
+
+ // If this is a term slug, get the term's nice name.
+ if ( taxonomy_exists( $attribute_key ) ) {
+ $term = get_term_by( 'slug', $meta_value, $attribute_key );
+ if ( ! is_wp_error( $term ) && is_object( $term ) && $term->name ) {
+ $meta_value = $term->name;
+ }
+ }
+
+ // Unique key required.
+ $formatted_meta_key = $meta_key;
+ $loop = 0;
+ while ( isset( $formatted_meta[ $formatted_meta_key ] ) ) {
+ $loop ++;
+ $formatted_meta_key = $meta_key . '-' . $loop;
+ }
+
+ $formatted_meta[ $formatted_meta_key ] = array(
+ 'key' => $meta_key,
+ 'label' => wc_attribute_label( $attribute_key, $this->product ),
+ 'value' => apply_filters( 'woocommerce_order_item_display_meta_value', $meta_value, $this->meta, $this->item ),
+ );
+ }
+ }
+
+ return $formatted_meta;
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-item-product.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-item-product.php
new file mode 100644
index 0000000..a32a626
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-item-product.php
@@ -0,0 +1,485 @@
+ 0,
+ 'variation_id' => 0,
+ 'quantity' => 1,
+ 'tax_class' => '',
+ 'subtotal' => 0,
+ 'subtotal_tax' => 0,
+ 'total' => 0,
+ 'total_tax' => 0,
+ 'taxes' => array(
+ 'subtotal' => array(),
+ 'total' => array(),
+ ),
+ );
+
+ /*
+ |--------------------------------------------------------------------------
+ | Setters
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Set quantity.
+ *
+ * @param int $value Quantity.
+ */
+ public function set_quantity( $value ) {
+ $this->set_prop( 'quantity', wc_stock_amount( $value ) );
+ }
+
+ /**
+ * Set tax class.
+ *
+ * @param string $value Tax class.
+ */
+ public function set_tax_class( $value ) {
+ if ( $value && ! in_array( $value, WC_Tax::get_tax_class_slugs(), true ) ) {
+ $this->error( 'order_item_product_invalid_tax_class', __( 'Invalid tax class', 'woocommerce' ) );
+ }
+ $this->set_prop( 'tax_class', $value );
+ }
+
+ /**
+ * Set Product ID
+ *
+ * @param int $value Product ID.
+ */
+ public function set_product_id( $value ) {
+ if ( $value > 0 && 'product' !== get_post_type( absint( $value ) ) ) {
+ $this->error( 'order_item_product_invalid_product_id', __( 'Invalid product ID', 'woocommerce' ) );
+ }
+ $this->set_prop( 'product_id', absint( $value ) );
+ }
+
+ /**
+ * Set variation ID.
+ *
+ * @param int $value Variation ID.
+ */
+ public function set_variation_id( $value ) {
+ if ( $value > 0 && 'product_variation' !== get_post_type( $value ) ) {
+ $this->error( 'order_item_product_invalid_variation_id', __( 'Invalid variation ID', 'woocommerce' ) );
+ }
+ $this->set_prop( 'variation_id', absint( $value ) );
+ }
+
+ /**
+ * Line subtotal (before discounts).
+ *
+ * @param string $value Subtotal.
+ */
+ public function set_subtotal( $value ) {
+ $value = wc_format_decimal( $value );
+
+ if ( ! is_numeric( $value ) ) {
+ $value = 0;
+ }
+
+ $this->set_prop( 'subtotal', $value );
+ }
+
+ /**
+ * Line total (after discounts).
+ *
+ * @param string $value Total.
+ */
+ public function set_total( $value ) {
+ $value = wc_format_decimal( $value );
+
+ if ( ! is_numeric( $value ) ) {
+ $value = 0;
+ }
+
+ $this->set_prop( 'total', $value );
+
+ // Subtotal cannot be less than total.
+ if ( '' === $this->get_subtotal() || $this->get_subtotal() < $this->get_total() ) {
+ $this->set_subtotal( $value );
+ }
+ }
+
+ /**
+ * Line subtotal tax (before discounts).
+ *
+ * @param string $value Subtotal tax.
+ */
+ public function set_subtotal_tax( $value ) {
+ $this->set_prop( 'subtotal_tax', wc_format_decimal( $value ) );
+ }
+
+ /**
+ * Line total tax (after discounts).
+ *
+ * @param string $value Total tax.
+ */
+ public function set_total_tax( $value ) {
+ $this->set_prop( 'total_tax', wc_format_decimal( $value ) );
+ }
+
+ /**
+ * Set line taxes and totals for passed in taxes.
+ *
+ * @param array $raw_tax_data Raw tax data.
+ */
+ public function set_taxes( $raw_tax_data ) {
+ $raw_tax_data = maybe_unserialize( $raw_tax_data );
+ $tax_data = array(
+ 'total' => array(),
+ 'subtotal' => array(),
+ );
+ if ( ! empty( $raw_tax_data['total'] ) && ! empty( $raw_tax_data['subtotal'] ) ) {
+ $tax_data['subtotal'] = array_map( 'wc_format_decimal', $raw_tax_data['subtotal'] );
+ $tax_data['total'] = array_map( 'wc_format_decimal', $raw_tax_data['total'] );
+
+ // Subtotal cannot be less than total!
+ if ( array_sum( $tax_data['subtotal'] ) < array_sum( $tax_data['total'] ) ) {
+ $tax_data['subtotal'] = $tax_data['total'];
+ }
+ }
+ $this->set_prop( 'taxes', $tax_data );
+
+ if ( 'yes' === get_option( 'woocommerce_tax_round_at_subtotal' ) ) {
+ $this->set_total_tax( array_sum( $tax_data['total'] ) );
+ $this->set_subtotal_tax( array_sum( $tax_data['subtotal'] ) );
+ } else {
+ $this->set_total_tax( array_sum( array_map( 'wc_round_tax_total', $tax_data['total'] ) ) );
+ $this->set_subtotal_tax( array_sum( array_map( 'wc_round_tax_total', $tax_data['subtotal'] ) ) );
+ }
+ }
+
+ /**
+ * Set variation data (stored as meta data - write only).
+ *
+ * @param array $data Key/Value pairs.
+ */
+ public function set_variation( $data = array() ) {
+ if ( is_array( $data ) ) {
+ foreach ( $data as $key => $value ) {
+ $this->add_meta_data( str_replace( 'attribute_', '', $key ), $value, true );
+ }
+ }
+ }
+
+ /**
+ * Set properties based on passed in product object.
+ *
+ * @param WC_Product $product Product instance.
+ */
+ public function set_product( $product ) {
+ if ( ! is_a( $product, 'WC_Product' ) ) {
+ $this->error( 'order_item_product_invalid_product', __( 'Invalid product', 'woocommerce' ) );
+ }
+ if ( $product->is_type( 'variation' ) ) {
+ $this->set_product_id( $product->get_parent_id() );
+ $this->set_variation_id( $product->get_id() );
+ $this->set_variation( is_callable( array( $product, 'get_variation_attributes' ) ) ? $product->get_variation_attributes() : array() );
+ } else {
+ $this->set_product_id( $product->get_id() );
+ }
+ $this->set_name( $product->get_name() );
+ $this->set_tax_class( $product->get_tax_class() );
+ }
+
+ /**
+ * Set meta data for backordered products.
+ */
+ public function set_backorder_meta() {
+ $product = $this->get_product();
+ if ( $product && $product->backorders_require_notification() && $product->is_on_backorder( $this->get_quantity() ) ) {
+ $this->add_meta_data( apply_filters( 'woocommerce_backordered_item_meta_name', __( 'Backordered', 'woocommerce' ), $this ), $this->get_quantity() - max( 0, $product->get_stock_quantity() ), true );
+ }
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Getters
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Get order item type.
+ *
+ * @return string
+ */
+ public function get_type() {
+ return 'line_item';
+ }
+
+ /**
+ * Get product ID.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return int
+ */
+ public function get_product_id( $context = 'view' ) {
+ return $this->get_prop( 'product_id', $context );
+ }
+
+ /**
+ * Get variation ID.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return int
+ */
+ public function get_variation_id( $context = 'view' ) {
+ return $this->get_prop( 'variation_id', $context );
+ }
+
+ /**
+ * Get quantity.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return int
+ */
+ public function get_quantity( $context = 'view' ) {
+ return $this->get_prop( 'quantity', $context );
+ }
+
+ /**
+ * Get tax class.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_tax_class( $context = 'view' ) {
+ return $this->get_prop( 'tax_class', $context );
+ }
+
+ /**
+ * Get subtotal.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_subtotal( $context = 'view' ) {
+ return $this->get_prop( 'subtotal', $context );
+ }
+
+ /**
+ * Get subtotal tax.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_subtotal_tax( $context = 'view' ) {
+ return $this->get_prop( 'subtotal_tax', $context );
+ }
+
+ /**
+ * Get total.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_total( $context = 'view' ) {
+ return $this->get_prop( 'total', $context );
+ }
+
+ /**
+ * Get total tax.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_total_tax( $context = 'view' ) {
+ return $this->get_prop( 'total_tax', $context );
+ }
+
+ /**
+ * Get taxes.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return array
+ */
+ public function get_taxes( $context = 'view' ) {
+ return $this->get_prop( 'taxes', $context );
+ }
+
+ /**
+ * Get the associated product.
+ *
+ * @return WC_Product|bool
+ */
+ public function get_product() {
+ if ( $this->get_variation_id() ) {
+ $product = wc_get_product( $this->get_variation_id() );
+ } else {
+ $product = wc_get_product( $this->get_product_id() );
+ }
+
+ // Backwards compatible filter from WC_Order::get_product_from_item().
+ if ( has_filter( 'woocommerce_get_product_from_item' ) ) {
+ $product = apply_filters( 'woocommerce_get_product_from_item', $product, $this, $this->get_order() );
+ }
+
+ return apply_filters( 'woocommerce_order_item_product', $product, $this );
+ }
+
+ /**
+ * Get the Download URL.
+ *
+ * @param int $download_id Download ID.
+ * @return string
+ */
+ public function get_item_download_url( $download_id ) {
+ $order = $this->get_order();
+
+ return $order ? add_query_arg(
+ array(
+ 'download_file' => $this->get_variation_id() ? $this->get_variation_id() : $this->get_product_id(),
+ 'order' => $order->get_order_key(),
+ 'email' => rawurlencode( $order->get_billing_email() ),
+ 'key' => $download_id,
+ ),
+ trailingslashit( home_url() )
+ ) : '';
+ }
+
+ /**
+ * Get any associated downloadable files.
+ *
+ * @return array
+ */
+ public function get_item_downloads() {
+ $files = array();
+ $product = $this->get_product();
+ $order = $this->get_order();
+ $product_id = $this->get_variation_id() ? $this->get_variation_id() : $this->get_product_id();
+
+ if ( $product && $order && $product->is_downloadable() && $order->is_download_permitted() ) {
+ $email_hash = function_exists( 'hash' ) ? hash( 'sha256', $order->get_billing_email() ) : sha1( $order->get_billing_email() );
+ $data_store = WC_Data_Store::load( 'customer-download' );
+ $customer_downloads = $data_store->get_downloads(
+ array(
+ 'user_email' => $order->get_billing_email(),
+ 'order_id' => $order->get_id(),
+ 'product_id' => $product_id,
+ )
+ );
+ foreach ( $customer_downloads as $customer_download ) {
+ $download_id = $customer_download->get_download_id();
+
+ if ( $product->has_file( $download_id ) ) {
+ $file = $product->get_file( $download_id );
+ $files[ $download_id ] = $file->get_data();
+ $files[ $download_id ]['downloads_remaining'] = $customer_download->get_downloads_remaining();
+ $files[ $download_id ]['access_expires'] = $customer_download->get_access_expires();
+ $files[ $download_id ]['download_url'] = add_query_arg(
+ array(
+ 'download_file' => $product_id,
+ 'order' => $order->get_order_key(),
+ 'uid' => $email_hash,
+ 'key' => $download_id,
+ ),
+ trailingslashit( home_url() )
+ );
+ }
+ }
+ }
+
+ return apply_filters( 'woocommerce_get_item_downloads', $files, $this, $order );
+ }
+
+ /**
+ * Get tax status.
+ *
+ * @return string
+ */
+ public function get_tax_status() {
+ $product = $this->get_product();
+ return $product ? $product->get_tax_status() : 'taxable';
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Array Access Methods
+ |--------------------------------------------------------------------------
+ |
+ | For backwards compatibility with legacy arrays.
+ |
+ */
+
+ /**
+ * OffsetGet for ArrayAccess/Backwards compatibility.
+ *
+ * @param string $offset Offset.
+ * @return mixed
+ */
+ public function offsetGet( $offset ) {
+ if ( 'line_subtotal' === $offset ) {
+ $offset = 'subtotal';
+ } elseif ( 'line_subtotal_tax' === $offset ) {
+ $offset = 'subtotal_tax';
+ } elseif ( 'line_total' === $offset ) {
+ $offset = 'total';
+ } elseif ( 'line_tax' === $offset ) {
+ $offset = 'total_tax';
+ } elseif ( 'line_tax_data' === $offset ) {
+ $offset = 'taxes';
+ } elseif ( 'qty' === $offset ) {
+ $offset = 'quantity';
+ }
+ return parent::offsetGet( $offset );
+ }
+
+ /**
+ * OffsetSet for ArrayAccess/Backwards compatibility.
+ *
+ * @deprecated 4.4.0
+ * @param string $offset Offset.
+ * @param mixed $value Value.
+ */
+ public function offsetSet( $offset, $value ) {
+ wc_deprecated_function( 'WC_Order_Item_Product::offsetSet', '4.4.0', '' );
+ if ( 'line_subtotal' === $offset ) {
+ $offset = 'subtotal';
+ } elseif ( 'line_subtotal_tax' === $offset ) {
+ $offset = 'subtotal_tax';
+ } elseif ( 'line_total' === $offset ) {
+ $offset = 'total';
+ } elseif ( 'line_tax' === $offset ) {
+ $offset = 'total_tax';
+ } elseif ( 'line_tax_data' === $offset ) {
+ $offset = 'taxes';
+ } elseif ( 'qty' === $offset ) {
+ $offset = 'quantity';
+ }
+ parent::offsetSet( $offset, $value );
+ }
+
+ /**
+ * OffsetExists for ArrayAccess.
+ *
+ * @param string $offset Offset.
+ * @return bool
+ */
+ public function offsetExists( $offset ) {
+ if ( in_array( $offset, array( 'line_subtotal', 'line_subtotal_tax', 'line_total', 'line_tax', 'line_tax_data', 'item_meta_array', 'item_meta', 'qty' ), true ) ) {
+ return true;
+ }
+ return parent::offsetExists( $offset );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-item-shipping.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-item-shipping.php
new file mode 100644
index 0000000..6602e87
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-item-shipping.php
@@ -0,0 +1,316 @@
+ '',
+ 'method_id' => '',
+ 'instance_id' => '',
+ 'total' => 0,
+ 'total_tax' => 0,
+ 'taxes' => array(
+ 'total' => array(),
+ ),
+ );
+
+ /**
+ * Calculate item taxes.
+ *
+ * @since 3.2.0
+ * @param array $calculate_tax_for Location data to get taxes for. Required.
+ * @return bool True if taxes were calculated.
+ */
+ public function calculate_taxes( $calculate_tax_for = array() ) {
+ if ( ! isset( $calculate_tax_for['country'], $calculate_tax_for['state'], $calculate_tax_for['postcode'], $calculate_tax_for['city'], $calculate_tax_for['tax_class'] ) ) {
+ return false;
+ }
+ if ( wc_tax_enabled() ) {
+ $tax_rates = WC_Tax::find_shipping_rates( $calculate_tax_for );
+ $taxes = WC_Tax::calc_tax( $this->get_total(), $tax_rates, false );
+ $this->set_taxes( array( 'total' => $taxes ) );
+ } else {
+ $this->set_taxes( false );
+ }
+
+ do_action( 'woocommerce_order_item_shipping_after_calculate_taxes', $this, $calculate_tax_for );
+
+ return true;
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Setters
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Set order item name.
+ *
+ * @param string $value Value to set.
+ * @throws WC_Data_Exception May throw exception if data is invalid.
+ */
+ public function set_name( $value ) {
+ $this->set_method_title( $value );
+ }
+
+ /**
+ * Set method title.
+ *
+ * @param string $value Value to set.
+ * @throws WC_Data_Exception May throw exception if data is invalid.
+ */
+ public function set_method_title( $value ) {
+ $this->set_prop( 'name', wc_clean( $value ) );
+ $this->set_prop( 'method_title', wc_clean( $value ) );
+ }
+
+ /**
+ * Set shipping method id.
+ *
+ * @param string $value Value to set.
+ * @throws WC_Data_Exception May throw exception if data is invalid.
+ */
+ public function set_method_id( $value ) {
+ $this->set_prop( 'method_id', wc_clean( $value ) );
+ }
+
+ /**
+ * Set shipping instance id.
+ *
+ * @param string $value Value to set.
+ * @throws WC_Data_Exception May throw exception if data is invalid.
+ */
+ public function set_instance_id( $value ) {
+ $this->set_prop( 'instance_id', wc_clean( $value ) );
+ }
+
+ /**
+ * Set total.
+ *
+ * @param string $value Value to set.
+ * @throws WC_Data_Exception May throw exception if data is invalid.
+ */
+ public function set_total( $value ) {
+ $this->set_prop( 'total', wc_format_decimal( $value ) );
+ }
+
+ /**
+ * Set total tax.
+ *
+ * @param string $value Value to set.
+ * @throws WC_Data_Exception May throw exception if data is invalid.
+ */
+ protected function set_total_tax( $value ) {
+ $this->set_prop( 'total_tax', wc_format_decimal( $value ) );
+ }
+
+ /**
+ * Set taxes.
+ *
+ * This is an array of tax ID keys with total amount values.
+ *
+ * @param array $raw_tax_data Value to set.
+ * @throws WC_Data_Exception May throw exception if data is invalid.
+ */
+ public function set_taxes( $raw_tax_data ) {
+ $raw_tax_data = maybe_unserialize( $raw_tax_data );
+ $tax_data = array(
+ 'total' => array(),
+ );
+ if ( isset( $raw_tax_data['total'] ) ) {
+ $tax_data['total'] = array_map( 'wc_format_decimal', $raw_tax_data['total'] );
+ } elseif ( ! empty( $raw_tax_data ) && is_array( $raw_tax_data ) ) {
+ // Older versions just used an array.
+ $tax_data['total'] = array_map( 'wc_format_decimal', $raw_tax_data );
+ }
+ $this->set_prop( 'taxes', $tax_data );
+
+ if ( 'yes' === get_option( 'woocommerce_tax_round_at_subtotal' ) ) {
+ $this->set_total_tax( array_sum( $tax_data['total'] ) );
+ } else {
+ $this->set_total_tax( array_sum( array_map( 'wc_round_tax_total', $tax_data['total'] ) ) );
+ }
+ }
+
+ /**
+ * Set properties based on passed in shipping rate object.
+ *
+ * @param WC_Shipping_Rate $shipping_rate Shipping rate to set.
+ */
+ public function set_shipping_rate( $shipping_rate ) {
+ $this->set_method_title( $shipping_rate->get_label() );
+ $this->set_method_id( $shipping_rate->get_method_id() );
+ $this->set_instance_id( $shipping_rate->get_instance_id() );
+ $this->set_total( $shipping_rate->get_cost() );
+ $this->set_taxes( $shipping_rate->get_taxes() );
+ $this->set_meta_data( $shipping_rate->get_meta_data() );
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Getters
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Get order item type.
+ *
+ * @return string
+ */
+ public function get_type() {
+ return 'shipping';
+ }
+
+ /**
+ * Get order item name.
+ *
+ * @param string $context View or edit context.
+ * @return string
+ */
+ public function get_name( $context = 'view' ) {
+ return $this->get_method_title( $context );
+ }
+
+ /**
+ * Get title.
+ *
+ * @param string $context View or edit context.
+ * @return string
+ */
+ public function get_method_title( $context = 'view' ) {
+ $method_title = $this->get_prop( 'method_title', $context );
+ if ( 'view' === $context ) {
+ return $method_title ? $method_title : __( 'Shipping', 'woocommerce' );
+ } else {
+ return $method_title;
+ }
+ }
+
+ /**
+ * Get method ID.
+ *
+ * @param string $context View or edit context.
+ * @return string
+ */
+ public function get_method_id( $context = 'view' ) {
+ return $this->get_prop( 'method_id', $context );
+ }
+
+ /**
+ * Get instance ID.
+ *
+ * @param string $context View or edit context.
+ * @return string
+ */
+ public function get_instance_id( $context = 'view' ) {
+ return $this->get_prop( 'instance_id', $context );
+ }
+
+ /**
+ * Get total cost.
+ *
+ * @param string $context View or edit context.
+ * @return string
+ */
+ public function get_total( $context = 'view' ) {
+ return $this->get_prop( 'total', $context );
+ }
+
+ /**
+ * Get total tax.
+ *
+ * @param string $context View or edit context.
+ * @return string
+ */
+ public function get_total_tax( $context = 'view' ) {
+ return $this->get_prop( 'total_tax', $context );
+ }
+
+ /**
+ * Get taxes.
+ *
+ * @param string $context View or edit context.
+ * @return array
+ */
+ public function get_taxes( $context = 'view' ) {
+ return $this->get_prop( 'taxes', $context );
+ }
+
+ /**
+ * Get tax class.
+ *
+ * @param string $context View or edit context.
+ * @return string
+ */
+ public function get_tax_class( $context = 'view' ) {
+ return get_option( 'woocommerce_shipping_tax_class' );
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Array Access Methods
+ |--------------------------------------------------------------------------
+ |
+ | For backwards compatibility with legacy arrays.
+ |
+ */
+
+ /**
+ * Offset get: for ArrayAccess/Backwards compatibility.
+ *
+ * @param string $offset Key.
+ * @return mixed
+ */
+ public function offsetGet( $offset ) {
+ if ( 'cost' === $offset ) {
+ $offset = 'total';
+ }
+ return parent::offsetGet( $offset );
+ }
+
+ /**
+ * Offset set: for ArrayAccess/Backwards compatibility.
+ *
+ * @deprecated 4.4.0
+ * @param string $offset Key.
+ * @param mixed $value Value to set.
+ */
+ public function offsetSet( $offset, $value ) {
+ wc_deprecated_function( 'WC_Order_Item_Shipping::offsetSet', '4.4.0', '' );
+ if ( 'cost' === $offset ) {
+ $offset = 'total';
+ }
+ parent::offsetSet( $offset, $value );
+ }
+
+ /**
+ * Offset exists: for ArrayAccess.
+ *
+ * @param string $offset Key.
+ * @return bool
+ */
+ public function offsetExists( $offset ) {
+ if ( in_array( $offset, array( 'cost' ), true ) ) {
+ return true;
+ }
+ return parent::offsetExists( $offset );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-item-tax.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-item-tax.php
new file mode 100644
index 0000000..c41e388
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-item-tax.php
@@ -0,0 +1,288 @@
+ '',
+ 'rate_id' => 0,
+ 'label' => '',
+ 'compound' => false,
+ 'tax_total' => 0,
+ 'shipping_tax_total' => 0,
+ 'rate_percent' => null,
+ );
+
+ /*
+ |--------------------------------------------------------------------------
+ | Setters
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Set order item name.
+ *
+ * @param string $value Name.
+ */
+ public function set_name( $value ) {
+ $this->set_rate_code( $value );
+ }
+
+ /**
+ * Set item name.
+ *
+ * @param string $value Rate code.
+ */
+ public function set_rate_code( $value ) {
+ $this->set_prop( 'rate_code', wc_clean( $value ) );
+ }
+
+ /**
+ * Set item name.
+ *
+ * @param string $value Label.
+ */
+ public function set_label( $value ) {
+ $this->set_prop( 'label', wc_clean( $value ) );
+ }
+
+ /**
+ * Set tax rate id.
+ *
+ * @param int $value Rate ID.
+ */
+ public function set_rate_id( $value ) {
+ $this->set_prop( 'rate_id', absint( $value ) );
+ }
+
+ /**
+ * Set tax total.
+ *
+ * @param string $value Tax total.
+ */
+ public function set_tax_total( $value ) {
+ $this->set_prop( 'tax_total', $value ? wc_format_decimal( $value ) : 0 );
+ }
+
+ /**
+ * Set shipping tax total.
+ *
+ * @param string $value Shipping tax total.
+ */
+ public function set_shipping_tax_total( $value ) {
+ $this->set_prop( 'shipping_tax_total', $value ? wc_format_decimal( $value ) : 0 );
+ }
+
+ /**
+ * Set compound.
+ *
+ * @param bool $value If tax is compound.
+ */
+ public function set_compound( $value ) {
+ $this->set_prop( 'compound', (bool) $value );
+ }
+
+ /**
+ * Set rate value.
+ *
+ * @param float $value tax rate value.
+ */
+ public function set_rate_percent( $value ) {
+ $this->set_prop( 'rate_percent', (float) $value );
+ }
+
+ /**
+ * Set properties based on passed in tax rate by ID.
+ *
+ * @param int $tax_rate_id Tax rate ID.
+ */
+ public function set_rate( $tax_rate_id ) {
+ $tax_rate = WC_Tax::_get_tax_rate( $tax_rate_id, OBJECT );
+
+ $this->set_rate_id( $tax_rate_id );
+ $this->set_rate_code( WC_Tax::get_rate_code( $tax_rate ) );
+ $this->set_label( WC_Tax::get_rate_label( $tax_rate ) );
+ $this->set_compound( WC_Tax::is_compound( $tax_rate ) );
+ $this->set_rate_percent( WC_Tax::get_rate_percent_value( $tax_rate ) );
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Getters
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Get order item type.
+ *
+ * @return string
+ */
+ public function get_type() {
+ return 'tax';
+ }
+
+ /**
+ * Get rate code/name.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_name( $context = 'view' ) {
+ return $this->get_rate_code( $context );
+ }
+
+ /**
+ * Get rate code/name.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_rate_code( $context = 'view' ) {
+ return $this->get_prop( 'rate_code', $context );
+ }
+
+ /**
+ * Get label.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_label( $context = 'view' ) {
+ $label = $this->get_prop( 'label', $context );
+ if ( 'view' === $context ) {
+ return $label ? $label : __( 'Tax', 'woocommerce' );
+ } else {
+ return $label;
+ }
+ }
+
+ /**
+ * Get tax rate ID.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return int
+ */
+ public function get_rate_id( $context = 'view' ) {
+ return $this->get_prop( 'rate_id', $context );
+ }
+
+ /**
+ * Get tax_total
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_tax_total( $context = 'view' ) {
+ return $this->get_prop( 'tax_total', $context );
+ }
+
+ /**
+ * Get shipping_tax_total
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_shipping_tax_total( $context = 'view' ) {
+ return $this->get_prop( 'shipping_tax_total', $context );
+ }
+
+ /**
+ * Get compound.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return bool
+ */
+ public function get_compound( $context = 'view' ) {
+ return $this->get_prop( 'compound', $context );
+ }
+
+ /**
+ * Is this a compound tax rate?
+ *
+ * @return boolean
+ */
+ public function is_compound() {
+ return $this->get_compound();
+ }
+
+ /**
+ * Get rate value
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return float
+ */
+ public function get_rate_percent( $context = 'view' ) {
+ return $this->get_prop( 'rate_percent', $context );
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Array Access Methods
+ |--------------------------------------------------------------------------
+ |
+ | For backwards compatibility with legacy arrays.
+ |
+ */
+
+ /**
+ * O for ArrayAccess/Backwards compatibility.
+ *
+ * @param string $offset Offset.
+ * @return mixed
+ */
+ public function offsetGet( $offset ) {
+ if ( 'tax_amount' === $offset ) {
+ $offset = 'tax_total';
+ } elseif ( 'shipping_tax_amount' === $offset ) {
+ $offset = 'shipping_tax_total';
+ }
+ return parent::offsetGet( $offset );
+ }
+
+ /**
+ * OffsetSet for ArrayAccess/Backwards compatibility.
+ *
+ * @deprecated 4.4.0
+ * @param string $offset Offset.
+ * @param mixed $value Value.
+ */
+ public function offsetSet( $offset, $value ) {
+ wc_deprecated_function( 'WC_Order_Item_Tax::offsetSet', '4.4.0', '' );
+ if ( 'tax_amount' === $offset ) {
+ $offset = 'tax_total';
+ } elseif ( 'shipping_tax_amount' === $offset ) {
+ $offset = 'shipping_tax_total';
+ }
+ parent::offsetSet( $offset, $value );
+ }
+
+ /**
+ * OffsetExists for ArrayAccess.
+ *
+ * @param string $offset Offset.
+ * @return bool
+ */
+ public function offsetExists( $offset ) {
+ if ( in_array( $offset, array( 'tax_amount', 'shipping_tax_amount' ), true ) ) {
+ return true;
+ }
+ return parent::offsetExists( $offset );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-item.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-item.php
new file mode 100644
index 0000000..e7c9161
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-item.php
@@ -0,0 +1,409 @@
+ 0,
+ 'name' => '',
+ );
+
+ /**
+ * Stores meta in cache for future reads.
+ * A group must be set to to enable caching.
+ *
+ * @var string
+ */
+ protected $cache_group = 'order-items';
+
+ /**
+ * Meta type. This should match up with
+ * the types available at https://developer.wordpress.org/reference/functions/add_metadata/.
+ * WP defines 'post', 'user', 'comment', and 'term'.
+ *
+ * @var string
+ */
+ protected $meta_type = 'order_item';
+
+ /**
+ * This is the name of this object type.
+ *
+ * @var string
+ */
+ protected $object_type = 'order_item';
+
+ /**
+ * Constructor.
+ *
+ * @param int|object|array $item ID to load from the DB, or WC_Order_Item object.
+ */
+ public function __construct( $item = 0 ) {
+ parent::__construct( $item );
+
+ if ( $item instanceof WC_Order_Item ) {
+ $this->set_id( $item->get_id() );
+ } elseif ( is_numeric( $item ) && $item > 0 ) {
+ $this->set_id( $item );
+ } else {
+ $this->set_object_read( true );
+ }
+
+ $type = 'line_item' === $this->get_type() ? 'product' : $this->get_type();
+ $this->data_store = WC_Data_Store::load( 'order-item-' . $type );
+ if ( $this->get_id() > 0 ) {
+ $this->data_store->read( $this );
+ }
+ }
+
+ /**
+ * Merge changes with data and clear.
+ * Overrides WC_Data::apply_changes.
+ * array_replace_recursive does not work well for order items because it merges taxes instead
+ * of replacing them.
+ *
+ * @since 3.2.0
+ */
+ public function apply_changes() {
+ if ( function_exists( 'array_replace' ) ) {
+ $this->data = array_replace( $this->data, $this->changes ); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctions.array_replaceFound
+ } else { // PHP 5.2 compatibility.
+ foreach ( $this->changes as $key => $change ) {
+ $this->data[ $key ] = $change;
+ }
+ }
+ $this->changes = array();
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Getters
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Get order ID this meta belongs to.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return int
+ */
+ public function get_order_id( $context = 'view' ) {
+ return $this->get_prop( 'order_id', $context );
+ }
+
+ /**
+ * Get order item name.
+ *
+ * @param string $context What the value is for. Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_name( $context = 'view' ) {
+ return $this->get_prop( 'name', $context );
+ }
+
+ /**
+ * Get order item type. Overridden by child classes.
+ *
+ * @return string
+ */
+ public function get_type() {
+ return '';
+ }
+
+ /**
+ * Get quantity.
+ *
+ * @return int
+ */
+ public function get_quantity() {
+ return 1;
+ }
+
+ /**
+ * Get tax status.
+ *
+ * @return string
+ */
+ public function get_tax_status() {
+ return 'taxable';
+ }
+
+ /**
+ * Get tax class.
+ *
+ * @return string
+ */
+ public function get_tax_class() {
+ return '';
+ }
+
+ /**
+ * Get parent order object.
+ *
+ * @return WC_Order
+ */
+ public function get_order() {
+ return wc_get_order( $this->get_order_id() );
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Setters
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Set order ID.
+ *
+ * @param int $value Order ID.
+ */
+ public function set_order_id( $value ) {
+ $this->set_prop( 'order_id', absint( $value ) );
+ }
+
+ /**
+ * Set order item name.
+ *
+ * @param string $value Item name.
+ */
+ public function set_name( $value ) {
+ $this->set_prop( 'name', wp_check_invalid_utf8( $value ) );
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Other Methods
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Type checking.
+ *
+ * @param string|array $type Type.
+ * @return boolean
+ */
+ public function is_type( $type ) {
+ return is_array( $type ) ? in_array( $this->get_type(), $type, true ) : $type === $this->get_type();
+ }
+
+ /**
+ * Calculate item taxes.
+ *
+ * @since 3.2.0
+ * @param array $calculate_tax_for Location data to get taxes for. Required.
+ * @return bool True if taxes were calculated.
+ */
+ public function calculate_taxes( $calculate_tax_for = array() ) {
+ if ( ! isset( $calculate_tax_for['country'], $calculate_tax_for['state'], $calculate_tax_for['postcode'], $calculate_tax_for['city'] ) ) {
+ return false;
+ }
+ if ( '0' !== $this->get_tax_class() && 'taxable' === $this->get_tax_status() && wc_tax_enabled() ) {
+ $calculate_tax_for['tax_class'] = $this->get_tax_class();
+ $tax_rates = WC_Tax::find_rates( $calculate_tax_for );
+ $taxes = WC_Tax::calc_tax( $this->get_total(), $tax_rates, false );
+
+ if ( method_exists( $this, 'get_subtotal' ) ) {
+ $subtotal_taxes = WC_Tax::calc_tax( $this->get_subtotal(), $tax_rates, false );
+ $this->set_taxes(
+ array(
+ 'total' => $taxes,
+ 'subtotal' => $subtotal_taxes,
+ )
+ );
+ } else {
+ $this->set_taxes( array( 'total' => $taxes ) );
+ }
+ } else {
+ $this->set_taxes( false );
+ }
+
+ do_action( 'woocommerce_order_item_after_calculate_taxes', $this, $calculate_tax_for );
+
+ return true;
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Meta Data Handling
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Expands things like term slugs before return.
+ *
+ * @param string $hideprefix Meta data prefix, (default: _).
+ * @param bool $include_all Include all meta data, this stop skip items with values already in the product name.
+ * @return array
+ */
+ public function get_formatted_meta_data( $hideprefix = '_', $include_all = false ) {
+ $formatted_meta = array();
+ $meta_data = $this->get_meta_data();
+ $hideprefix_length = ! empty( $hideprefix ) ? strlen( $hideprefix ) : 0;
+ $product = is_callable( array( $this, 'get_product' ) ) ? $this->get_product() : false;
+ $order_item_name = $this->get_name();
+
+ foreach ( $meta_data as $meta ) {
+ if ( empty( $meta->id ) || '' === $meta->value || ! is_scalar( $meta->value ) || ( $hideprefix_length && substr( $meta->key, 0, $hideprefix_length ) === $hideprefix ) ) {
+ continue;
+ }
+
+ $meta->key = rawurldecode( (string) $meta->key );
+ $meta->value = rawurldecode( (string) $meta->value );
+ $attribute_key = str_replace( 'attribute_', '', $meta->key );
+ $display_key = wc_attribute_label( $attribute_key, $product );
+ $display_value = wp_kses_post( $meta->value );
+
+ if ( taxonomy_exists( $attribute_key ) ) {
+ $term = get_term_by( 'slug', $meta->value, $attribute_key );
+ if ( ! is_wp_error( $term ) && is_object( $term ) && $term->name ) {
+ $display_value = $term->name;
+ }
+ }
+
+ // Skip items with values already in the product details area of the product name.
+ if ( ! $include_all && $product && $product->is_type( 'variation' ) && wc_is_attribute_in_product_name( $display_value, $order_item_name ) ) {
+ continue;
+ }
+
+ $formatted_meta[ $meta->id ] = (object) array(
+ 'key' => $meta->key,
+ 'value' => $meta->value,
+ 'display_key' => apply_filters( 'woocommerce_order_item_display_meta_key', $display_key, $meta, $this ),
+ 'display_value' => wpautop( make_clickable( apply_filters( 'woocommerce_order_item_display_meta_value', $display_value, $meta, $this ) ) ),
+ );
+ }
+
+ return apply_filters( 'woocommerce_order_item_get_formatted_meta_data', $formatted_meta, $this );
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Array Access Methods
+ |--------------------------------------------------------------------------
+ |
+ | For backwards compatibility with legacy arrays.
+ |
+ */
+
+ /**
+ * OffsetSet for ArrayAccess.
+ *
+ * @param string $offset Offset.
+ * @param mixed $value Value.
+ */
+ public function offsetSet( $offset, $value ) {
+ if ( 'item_meta_array' === $offset ) {
+ foreach ( $value as $meta_id => $meta ) {
+ $this->update_meta_data( $meta->key, $meta->value, $meta_id );
+ }
+ return;
+ }
+
+ if ( array_key_exists( $offset, $this->data ) ) {
+ $setter = "set_$offset";
+ if ( is_callable( array( $this, $setter ) ) ) {
+ $this->$setter( $value );
+ }
+ return;
+ }
+
+ $this->update_meta_data( $offset, $value );
+ }
+
+ /**
+ * OffsetUnset for ArrayAccess.
+ *
+ * @param string $offset Offset.
+ */
+ public function offsetUnset( $offset ) {
+ $this->maybe_read_meta_data();
+
+ if ( 'item_meta_array' === $offset || 'item_meta' === $offset ) {
+ $this->meta_data = array();
+ return;
+ }
+
+ if ( array_key_exists( $offset, $this->data ) ) {
+ unset( $this->data[ $offset ] );
+ }
+
+ if ( array_key_exists( $offset, $this->changes ) ) {
+ unset( $this->changes[ $offset ] );
+ }
+
+ $this->delete_meta_data( $offset );
+ }
+
+ /**
+ * OffsetExists for ArrayAccess.
+ *
+ * @param string $offset Offset.
+ * @return bool
+ */
+ public function offsetExists( $offset ) {
+ $this->maybe_read_meta_data();
+ if ( 'item_meta_array' === $offset || 'item_meta' === $offset || array_key_exists( $offset, $this->data ) ) {
+ return true;
+ }
+ return array_key_exists( $offset, wp_list_pluck( $this->meta_data, 'value', 'key' ) ) || array_key_exists( '_' . $offset, wp_list_pluck( $this->meta_data, 'value', 'key' ) );
+ }
+
+ /**
+ * OffsetGet for ArrayAccess.
+ *
+ * @param string $offset Offset.
+ * @return mixed
+ */
+ public function offsetGet( $offset ) {
+ $this->maybe_read_meta_data();
+
+ if ( 'item_meta_array' === $offset ) {
+ $return = array();
+
+ foreach ( $this->meta_data as $meta ) {
+ $return[ $meta->id ] = $meta;
+ }
+
+ return $return;
+ }
+
+ $meta_values = wp_list_pluck( $this->meta_data, 'value', 'key' );
+
+ if ( 'item_meta' === $offset ) {
+ return $meta_values;
+ } elseif ( 'type' === $offset ) {
+ return $this->get_type();
+ } elseif ( array_key_exists( $offset, $this->data ) ) {
+ $getter = "get_$offset";
+ if ( is_callable( array( $this, $getter ) ) ) {
+ return $this->$getter();
+ }
+ } elseif ( array_key_exists( '_' . $offset, $meta_values ) ) {
+ // Item meta was expanded in previous versions, with prefixes removed. This maintains support.
+ return $meta_values[ '_' . $offset ];
+ } elseif ( array_key_exists( $offset, $meta_values ) ) {
+ return $meta_values[ $offset ];
+ }
+
+ return null;
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-query.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-query.php
new file mode 100644
index 0000000..4f481c8
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-query.php
@@ -0,0 +1,89 @@
+ array_keys( wc_get_order_statuses() ),
+ 'type' => wc_get_order_types( 'view-orders' ),
+ 'currency' => '',
+ 'version' => '',
+ 'prices_include_tax' => '',
+ 'date_created' => '',
+ 'date_modified' => '',
+ 'date_completed' => '',
+ 'date_paid' => '',
+ 'discount_total' => '',
+ 'discount_tax' => '',
+ 'shipping_total' => '',
+ 'shipping_tax' => '',
+ 'cart_tax' => '',
+ 'total' => '',
+ 'total_tax' => '',
+ 'customer' => '',
+ 'customer_id' => '',
+ 'order_key' => '',
+ 'billing_first_name' => '',
+ 'billing_last_name' => '',
+ 'billing_company' => '',
+ 'billing_address_1' => '',
+ 'billing_address_2' => '',
+ 'billing_city' => '',
+ 'billing_state' => '',
+ 'billing_postcode' => '',
+ 'billing_country' => '',
+ 'billing_email' => '',
+ 'billing_phone' => '',
+ 'shipping_first_name' => '',
+ 'shipping_last_name' => '',
+ 'shipping_company' => '',
+ 'shipping_address_1' => '',
+ 'shipping_address_2' => '',
+ 'shipping_city' => '',
+ 'shipping_state' => '',
+ 'shipping_postcode' => '',
+ 'shipping_country' => '',
+ 'payment_method' => '',
+ 'payment_method_title' => '',
+ 'transaction_id' => '',
+ 'customer_ip_address' => '',
+ 'customer_user_agent' => '',
+ 'created_via' => '',
+ 'customer_note' => '',
+ )
+ );
+ }
+
+ /**
+ * Get orders matching the current query vars.
+ *
+ * @return array|object of WC_Order objects
+ *
+ * @throws Exception When WC_Data_Store validation fails.
+ */
+ public function get_orders() {
+ $args = apply_filters( 'woocommerce_order_query_args', $this->get_query_vars() );
+ $results = WC_Data_Store::load( 'order' )->query( $args );
+ return apply_filters( 'woocommerce_order_query', $results, $args );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-refund.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-refund.php
new file mode 100644
index 0000000..c384d04
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order-refund.php
@@ -0,0 +1,228 @@
+ '',
+ 'reason' => '',
+ 'refunded_by' => 0,
+ 'refunded_payment' => false,
+ );
+
+ /**
+ * Get internal type (post type.)
+ *
+ * @return string
+ */
+ public function get_type() {
+ return 'shop_order_refund';
+ }
+
+ /**
+ * Get status - always completed for refunds.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_status( $context = 'view' ) {
+ return 'completed';
+ }
+
+ /**
+ * Get a title for the new post type.
+ */
+ public function get_post_title() {
+ // @codingStandardsIgnoreStart
+ return sprintf( __( 'Refund – %s', 'woocommerce' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Order date parsed by strftime', 'woocommerce' ) ) );
+ // @codingStandardsIgnoreEnd
+ }
+
+ /**
+ * Get refunded amount.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return int|float
+ */
+ public function get_amount( $context = 'view' ) {
+ return $this->get_prop( 'amount', $context );
+ }
+
+ /**
+ * Get refund reason.
+ *
+ * @since 2.2
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return int|float
+ */
+ public function get_reason( $context = 'view' ) {
+ return $this->get_prop( 'reason', $context );
+ }
+
+ /**
+ * Get ID of user who did the refund.
+ *
+ * @since 3.0
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return int
+ */
+ public function get_refunded_by( $context = 'view' ) {
+ return $this->get_prop( 'refunded_by', $context );
+ }
+
+ /**
+ * Return if the payment was refunded via API.
+ *
+ * @since 3.3
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return bool
+ */
+ public function get_refunded_payment( $context = 'view' ) {
+ return $this->get_prop( 'refunded_payment', $context );
+ }
+
+ /**
+ * Get formatted refunded amount.
+ *
+ * @since 2.4
+ * @return string
+ */
+ public function get_formatted_refund_amount() {
+ return apply_filters( 'woocommerce_formatted_refund_amount', wc_price( $this->get_amount(), array( 'currency' => $this->get_currency() ) ), $this );
+ }
+
+ /**
+ * Set refunded amount.
+ *
+ * @param string $value Value to set.
+ * @throws WC_Data_Exception Exception if the amount is invalid.
+ */
+ public function set_amount( $value ) {
+ $this->set_prop( 'amount', wc_format_decimal( $value ) );
+ }
+
+ /**
+ * Set refund reason.
+ *
+ * @param string $value Value to set.
+ * @throws WC_Data_Exception Exception if the amount is invalid.
+ */
+ public function set_reason( $value ) {
+ $this->set_prop( 'reason', $value );
+ }
+
+ /**
+ * Set refunded by.
+ *
+ * @param int $value Value to set.
+ * @throws WC_Data_Exception Exception if the amount is invalid.
+ */
+ public function set_refunded_by( $value ) {
+ $this->set_prop( 'refunded_by', absint( $value ) );
+ }
+
+ /**
+ * Set if the payment was refunded via API.
+ *
+ * @since 3.3
+ * @param bool $value Value to set.
+ */
+ public function set_refunded_payment( $value ) {
+ $this->set_prop( 'refunded_payment', (bool) $value );
+ }
+
+ /**
+ * Magic __get method for backwards compatibility.
+ *
+ * @param string $key Value to get.
+ * @return mixed
+ */
+ public function __get( $key ) {
+ wc_doing_it_wrong( $key, 'Refund properties should not be accessed directly.', '3.0' );
+ /**
+ * Maps legacy vars to new getters.
+ */
+ if ( 'reason' === $key ) {
+ return $this->get_reason();
+ } elseif ( 'refund_amount' === $key ) {
+ return $this->get_amount();
+ }
+ return parent::__get( $key );
+ }
+
+ /**
+ * Gets an refund from the database.
+ *
+ * @deprecated 3.0
+ * @param int $id (default: 0).
+ * @return bool
+ */
+ public function get_refund( $id = 0 ) {
+ wc_deprecated_function( 'get_refund', '3.0', 'read' );
+
+ if ( ! $id ) {
+ return false;
+ }
+
+ $result = get_post( $id );
+
+ if ( $result ) {
+ $this->populate( $result );
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Get refund amount.
+ *
+ * @deprecated 3.0
+ * @return int|float
+ */
+ public function get_refund_amount() {
+ wc_deprecated_function( 'get_refund_amount', '3.0', 'get_amount' );
+ return $this->get_amount();
+ }
+
+ /**
+ * Get refund reason.
+ *
+ * @deprecated 3.0
+ * @return int|float
+ */
+ public function get_refund_reason() {
+ wc_deprecated_function( 'get_refund_reason', '3.0', 'get_reason' );
+ return $this->get_reason();
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order.php
new file mode 100644
index 0000000..f33c5db
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-order.php
@@ -0,0 +1,2091 @@
+ 0,
+ 'status' => '',
+ 'currency' => '',
+ 'version' => '',
+ 'prices_include_tax' => false,
+ 'date_created' => null,
+ 'date_modified' => null,
+ 'discount_total' => 0,
+ 'discount_tax' => 0,
+ 'shipping_total' => 0,
+ 'shipping_tax' => 0,
+ 'cart_tax' => 0,
+ 'total' => 0,
+ 'total_tax' => 0,
+
+ // Order props.
+ 'customer_id' => 0,
+ 'order_key' => '',
+ 'billing' => array(
+ 'first_name' => '',
+ 'last_name' => '',
+ 'company' => '',
+ 'address_1' => '',
+ 'address_2' => '',
+ 'city' => '',
+ 'state' => '',
+ 'postcode' => '',
+ 'country' => '',
+ 'email' => '',
+ 'phone' => '',
+ ),
+ 'shipping' => array(
+ 'first_name' => '',
+ 'last_name' => '',
+ 'company' => '',
+ 'address_1' => '',
+ 'address_2' => '',
+ 'city' => '',
+ 'state' => '',
+ 'postcode' => '',
+ 'country' => '',
+ ),
+ 'payment_method' => '',
+ 'payment_method_title' => '',
+ 'transaction_id' => '',
+ 'customer_ip_address' => '',
+ 'customer_user_agent' => '',
+ 'created_via' => '',
+ 'customer_note' => '',
+ 'date_completed' => null,
+ 'date_paid' => null,
+ 'cart_hash' => '',
+ );
+
+ /**
+ * When a payment is complete this function is called.
+ *
+ * Most of the time this should mark an order as 'processing' so that admin can process/post the items.
+ * If the cart contains only downloadable items then the order is 'completed' since the admin needs to take no action.
+ * Stock levels are reduced at this point.
+ * Sales are also recorded for products.
+ * Finally, record the date of payment.
+ *
+ * @param string $transaction_id Optional transaction id to store in post meta.
+ * @return bool success
+ */
+ public function payment_complete( $transaction_id = '' ) {
+ if ( ! $this->get_id() ) { // Order must exist.
+ return false;
+ }
+
+ try {
+ do_action( 'woocommerce_pre_payment_complete', $this->get_id() );
+
+ if ( WC()->session ) {
+ WC()->session->set( 'order_awaiting_payment', false );
+ }
+
+ if ( $this->has_status( apply_filters( 'woocommerce_valid_order_statuses_for_payment_complete', array( 'on-hold', 'pending', 'failed', 'cancelled' ), $this ) ) ) {
+ if ( ! empty( $transaction_id ) ) {
+ $this->set_transaction_id( $transaction_id );
+ }
+ if ( ! $this->get_date_paid( 'edit' ) ) {
+ $this->set_date_paid( time() );
+ }
+ $this->set_status( apply_filters( 'woocommerce_payment_complete_order_status', $this->needs_processing() ? 'processing' : 'completed', $this->get_id(), $this ) );
+ $this->save();
+
+ do_action( 'woocommerce_payment_complete', $this->get_id() );
+ } else {
+ do_action( 'woocommerce_payment_complete_order_status_' . $this->get_status(), $this->get_id() );
+ }
+ } catch ( Exception $e ) {
+ /**
+ * If there was an error completing the payment, log to a file and add an order note so the admin can take action.
+ */
+ $logger = wc_get_logger();
+ $logger->error(
+ sprintf(
+ 'Error completing payment for order #%d',
+ $this->get_id()
+ ),
+ array(
+ 'order' => $this,
+ 'error' => $e,
+ )
+ );
+ $this->add_order_note( __( 'Payment complete event failed.', 'woocommerce' ) . ' ' . $e->getMessage() );
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Gets order total - formatted for display.
+ *
+ * @param string $tax_display Type of tax display.
+ * @param bool $display_refunded If should include refunded value.
+ *
+ * @return string
+ */
+ public function get_formatted_order_total( $tax_display = '', $display_refunded = true ) {
+ $formatted_total = wc_price( $this->get_total(), array( 'currency' => $this->get_currency() ) );
+ $order_total = $this->get_total();
+ $total_refunded = $this->get_total_refunded();
+ $tax_string = '';
+
+ // Tax for inclusive prices.
+ if ( wc_tax_enabled() && 'incl' === $tax_display ) {
+ $tax_string_array = array();
+ $tax_totals = $this->get_tax_totals();
+
+ if ( 'itemized' === get_option( 'woocommerce_tax_total_display' ) ) {
+ foreach ( $tax_totals as $code => $tax ) {
+ $tax_amount = ( $total_refunded && $display_refunded ) ? wc_price( WC_Tax::round( $tax->amount - $this->get_total_tax_refunded_by_rate_id( $tax->rate_id ) ), array( 'currency' => $this->get_currency() ) ) : $tax->formatted_amount;
+ $tax_string_array[] = sprintf( '%s %s', $tax_amount, $tax->label );
+ }
+ } elseif ( ! empty( $tax_totals ) ) {
+ $tax_amount = ( $total_refunded && $display_refunded ) ? $this->get_total_tax() - $this->get_total_tax_refunded() : $this->get_total_tax();
+ $tax_string_array[] = sprintf( '%s %s', wc_price( $tax_amount, array( 'currency' => $this->get_currency() ) ), WC()->countries->tax_or_vat() );
+ }
+
+ if ( ! empty( $tax_string_array ) ) {
+ /* translators: %s: taxes */
+ $tax_string = ' ' . sprintf( __( '(includes %s)', 'woocommerce' ), implode( ', ', $tax_string_array ) ) . '';
+ }
+ }
+
+ if ( $total_refunded && $display_refunded ) {
+ $formatted_total = '' . wp_strip_all_tags( $formatted_total ) . ' ' . wc_price( $order_total - $total_refunded, array( 'currency' => $this->get_currency() ) ) . $tax_string . '';
+ } else {
+ $formatted_total .= $tax_string;
+ }
+
+ /**
+ * Filter WooCommerce formatted order total.
+ *
+ * @param string $formatted_total Total to display.
+ * @param WC_Order $order Order data.
+ * @param string $tax_display Type of tax display.
+ * @param bool $display_refunded If should include refunded value.
+ */
+ return apply_filters( 'woocommerce_get_formatted_order_total', $formatted_total, $this, $tax_display, $display_refunded );
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | CRUD methods
+ |--------------------------------------------------------------------------
+ |
+ | Methods which create, read, update and delete orders from the database.
+ | Written in abstract fashion so that the way orders are stored can be
+ | changed more easily in the future.
+ |
+ | A save method is included for convenience (chooses update or create based
+ | on if the order exists yet).
+ |
+ */
+
+ /**
+ * Save data to the database.
+ *
+ * @since 3.0.0
+ * @return int order ID
+ */
+ public function save() {
+ $this->maybe_set_user_billing_email();
+ parent::save();
+ $this->status_transition();
+
+ return $this->get_id();
+ }
+
+ /**
+ * Log an error about this order is exception is encountered.
+ *
+ * @param Exception $e Exception object.
+ * @param string $message Message regarding exception thrown.
+ * @since 3.7.0
+ */
+ protected function handle_exception( $e, $message = 'Error' ) {
+ wc_get_logger()->error(
+ $message,
+ array(
+ 'order' => $this,
+ 'error' => $e,
+ )
+ );
+ $this->add_order_note( $message . ' ' . $e->getMessage() );
+ }
+
+ /**
+ * Set order status.
+ *
+ * @since 3.0.0
+ * @param string $new_status Status to change the order to. No internal wc- prefix is required.
+ * @param string $note Optional note to add.
+ * @param bool $manual_update Is this a manual order status change?.
+ * @return array
+ */
+ public function set_status( $new_status, $note = '', $manual_update = false ) {
+ $result = parent::set_status( $new_status );
+
+ if ( true === $this->object_read && ! empty( $result['from'] ) && $result['from'] !== $result['to'] ) {
+ $this->status_transition = array(
+ 'from' => ! empty( $this->status_transition['from'] ) ? $this->status_transition['from'] : $result['from'],
+ 'to' => $result['to'],
+ 'note' => $note,
+ 'manual' => (bool) $manual_update,
+ );
+
+ if ( $manual_update ) {
+ do_action( 'woocommerce_order_edit_status', $this->get_id(), $result['to'] );
+ }
+
+ $this->maybe_set_date_paid();
+ $this->maybe_set_date_completed();
+ }
+
+ return $result;
+ }
+
+ /**
+ * Maybe set date paid.
+ *
+ * Sets the date paid variable when transitioning to the payment complete
+ * order status. This is either processing or completed. This is not filtered
+ * to avoid infinite loops e.g. if loading an order via the filter.
+ *
+ * Date paid is set once in this manner - only when it is not already set.
+ * This ensures the data exists even if a gateway does not use the
+ * `payment_complete` method.
+ *
+ * @since 3.0.0
+ */
+ public function maybe_set_date_paid() {
+ // This logic only runs if the date_paid prop has not been set yet.
+ if ( ! $this->get_date_paid( 'edit' ) ) {
+ $payment_completed_status = apply_filters( 'woocommerce_payment_complete_order_status', $this->needs_processing() ? 'processing' : 'completed', $this->get_id(), $this );
+
+ if ( $this->has_status( $payment_completed_status ) ) {
+ // If payment complete status is reached, set paid now.
+ $this->set_date_paid( time() );
+
+ } elseif ( 'processing' === $payment_completed_status && $this->has_status( 'completed' ) ) {
+ // If payment complete status was processing, but we've passed that and still have no date, set it now.
+ $this->set_date_paid( time() );
+ }
+ }
+ }
+
+ /**
+ * Maybe set date completed.
+ *
+ * Sets the date completed variable when transitioning to completed status.
+ *
+ * @since 3.0.0
+ */
+ protected function maybe_set_date_completed() {
+ if ( $this->has_status( 'completed' ) ) {
+ $this->set_date_completed( time() );
+ }
+ }
+
+ /**
+ * Updates status of order immediately.
+ *
+ * @uses WC_Order::set_status()
+ * @param string $new_status Status to change the order to. No internal wc- prefix is required.
+ * @param string $note Optional note to add.
+ * @param bool $manual Is this a manual order status change?.
+ * @return bool
+ */
+ public function update_status( $new_status, $note = '', $manual = false ) {
+ if ( ! $this->get_id() ) { // Order must exist.
+ return false;
+ }
+
+ try {
+ $this->set_status( $new_status, $note, $manual );
+ $this->save();
+ } catch ( Exception $e ) {
+ $logger = wc_get_logger();
+ $logger->error(
+ sprintf(
+ 'Error updating status for order #%d',
+ $this->get_id()
+ ),
+ array(
+ 'order' => $this,
+ 'error' => $e,
+ )
+ );
+ $this->add_order_note( __( 'Update status event failed.', 'woocommerce' ) . ' ' . $e->getMessage() );
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Handle the status transition.
+ */
+ protected function status_transition() {
+ $status_transition = $this->status_transition;
+
+ // Reset status transition variable.
+ $this->status_transition = false;
+
+ if ( $status_transition ) {
+ try {
+ do_action( 'woocommerce_order_status_' . $status_transition['to'], $this->get_id(), $this );
+
+ if ( ! empty( $status_transition['from'] ) ) {
+ /* translators: 1: old order status 2: new order status */
+ $transition_note = sprintf( __( 'Order status changed from %1$s to %2$s.', 'woocommerce' ), wc_get_order_status_name( $status_transition['from'] ), wc_get_order_status_name( $status_transition['to'] ) );
+
+ // Note the transition occurred.
+ $this->add_status_transition_note( $transition_note, $status_transition );
+
+ do_action( 'woocommerce_order_status_' . $status_transition['from'] . '_to_' . $status_transition['to'], $this->get_id(), $this );
+ do_action( 'woocommerce_order_status_changed', $this->get_id(), $status_transition['from'], $status_transition['to'], $this );
+
+ // Work out if this was for a payment, and trigger a payment_status hook instead.
+ if (
+ in_array( $status_transition['from'], apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'failed' ), $this ), true )
+ && in_array( $status_transition['to'], wc_get_is_paid_statuses(), true )
+ ) {
+ /**
+ * Fires when the order progresses from a pending payment status to a paid one.
+ *
+ * @since 3.9.0
+ * @param int Order ID
+ * @param WC_Order Order object
+ */
+ do_action( 'woocommerce_order_payment_status_changed', $this->get_id(), $this );
+ }
+ } else {
+ /* translators: %s: new order status */
+ $transition_note = sprintf( __( 'Order status set to %s.', 'woocommerce' ), wc_get_order_status_name( $status_transition['to'] ) );
+
+ // Note the transition occurred.
+ $this->add_status_transition_note( $transition_note, $status_transition );
+ }
+ } catch ( Exception $e ) {
+ $logger = wc_get_logger();
+ $logger->error(
+ sprintf(
+ 'Status transition of order #%d errored!',
+ $this->get_id()
+ ),
+ array(
+ 'order' => $this,
+ 'error' => $e,
+ )
+ );
+ $this->add_order_note( __( 'Error during status transition.', 'woocommerce' ) . ' ' . $e->getMessage() );
+ }
+ }
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Getters
+ |--------------------------------------------------------------------------
+ |
+ | Methods for getting data from the order object.
+ |
+ */
+
+ /**
+ * Get basic order data in array format.
+ *
+ * @return array
+ */
+ public function get_base_data() {
+ return array_merge(
+ array( 'id' => $this->get_id() ),
+ $this->data,
+ array( 'number' => $this->get_order_number() )
+ );
+ }
+
+ /**
+ * Get all class data in array format.
+ *
+ * @since 3.0.0
+ * @return array
+ */
+ public function get_data() {
+ return array_merge(
+ $this->get_base_data(),
+ array(
+ 'meta_data' => $this->get_meta_data(),
+ 'line_items' => $this->get_items( 'line_item' ),
+ 'tax_lines' => $this->get_items( 'tax' ),
+ 'shipping_lines' => $this->get_items( 'shipping' ),
+ 'fee_lines' => $this->get_items( 'fee' ),
+ 'coupon_lines' => $this->get_items( 'coupon' ),
+ )
+ );
+ }
+
+ /**
+ * Expands the shipping and billing information in the changes array.
+ */
+ public function get_changes() {
+ $changed_props = parent::get_changes();
+ $subs = array( 'shipping', 'billing' );
+ foreach ( $subs as $sub ) {
+ if ( ! empty( $changed_props[ $sub ] ) ) {
+ foreach ( $changed_props[ $sub ] as $sub_prop => $value ) {
+ $changed_props[ $sub . '_' . $sub_prop ] = $value;
+ }
+ }
+ }
+ if ( isset( $changed_props['customer_note'] ) ) {
+ $changed_props['post_excerpt'] = $changed_props['customer_note'];
+ }
+ return $changed_props;
+ }
+
+ /**
+ * Gets the order number for display (by default, order ID).
+ *
+ * @return string
+ */
+ public function get_order_number() {
+ return (string) apply_filters( 'woocommerce_order_number', $this->get_id(), $this );
+ }
+
+ /**
+ * Get order key.
+ *
+ * @since 3.0.0
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_order_key( $context = 'view' ) {
+ return $this->get_prop( 'order_key', $context );
+ }
+
+ /**
+ * Get customer_id.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return int
+ */
+ public function get_customer_id( $context = 'view' ) {
+ return $this->get_prop( 'customer_id', $context );
+ }
+
+ /**
+ * Alias for get_customer_id().
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return int
+ */
+ public function get_user_id( $context = 'view' ) {
+ return $this->get_customer_id( $context );
+ }
+
+ /**
+ * Get the user associated with the order. False for guests.
+ *
+ * @return WP_User|false
+ */
+ public function get_user() {
+ return $this->get_user_id() ? get_user_by( 'id', $this->get_user_id() ) : false;
+ }
+
+ /**
+ * Gets a prop for a getter method.
+ *
+ * @since 3.0.0
+ * @param string $prop Name of prop to get.
+ * @param string $address billing or shipping.
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return mixed
+ */
+ protected function get_address_prop( $prop, $address = 'billing', $context = 'view' ) {
+ $value = null;
+
+ if ( array_key_exists( $prop, $this->data[ $address ] ) ) {
+ $value = isset( $this->changes[ $address ][ $prop ] ) ? $this->changes[ $address ][ $prop ] : $this->data[ $address ][ $prop ];
+
+ if ( 'view' === $context ) {
+ $value = apply_filters( $this->get_hook_prefix() . $address . '_' . $prop, $value, $this );
+ }
+ }
+ return $value;
+ }
+
+ /**
+ * Get billing first name.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_billing_first_name( $context = 'view' ) {
+ return $this->get_address_prop( 'first_name', 'billing', $context );
+ }
+
+ /**
+ * Get billing last name.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_billing_last_name( $context = 'view' ) {
+ return $this->get_address_prop( 'last_name', 'billing', $context );
+ }
+
+ /**
+ * Get billing company.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_billing_company( $context = 'view' ) {
+ return $this->get_address_prop( 'company', 'billing', $context );
+ }
+
+ /**
+ * Get billing address line 1.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_billing_address_1( $context = 'view' ) {
+ return $this->get_address_prop( 'address_1', 'billing', $context );
+ }
+
+ /**
+ * Get billing address line 2.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_billing_address_2( $context = 'view' ) {
+ return $this->get_address_prop( 'address_2', 'billing', $context );
+ }
+
+ /**
+ * Get billing city.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_billing_city( $context = 'view' ) {
+ return $this->get_address_prop( 'city', 'billing', $context );
+ }
+
+ /**
+ * Get billing state.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_billing_state( $context = 'view' ) {
+ return $this->get_address_prop( 'state', 'billing', $context );
+ }
+
+ /**
+ * Get billing postcode.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_billing_postcode( $context = 'view' ) {
+ return $this->get_address_prop( 'postcode', 'billing', $context );
+ }
+
+ /**
+ * Get billing country.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_billing_country( $context = 'view' ) {
+ return $this->get_address_prop( 'country', 'billing', $context );
+ }
+
+ /**
+ * Get billing email.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_billing_email( $context = 'view' ) {
+ return $this->get_address_prop( 'email', 'billing', $context );
+ }
+
+ /**
+ * Get billing phone.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_billing_phone( $context = 'view' ) {
+ return $this->get_address_prop( 'phone', 'billing', $context );
+ }
+
+ /**
+ * Get shipping first name.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_shipping_first_name( $context = 'view' ) {
+ return $this->get_address_prop( 'first_name', 'shipping', $context );
+ }
+
+ /**
+ * Get shipping_last_name.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_shipping_last_name( $context = 'view' ) {
+ return $this->get_address_prop( 'last_name', 'shipping', $context );
+ }
+
+ /**
+ * Get shipping company.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_shipping_company( $context = 'view' ) {
+ return $this->get_address_prop( 'company', 'shipping', $context );
+ }
+
+ /**
+ * Get shipping address line 1.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_shipping_address_1( $context = 'view' ) {
+ return $this->get_address_prop( 'address_1', 'shipping', $context );
+ }
+
+ /**
+ * Get shipping address line 2.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_shipping_address_2( $context = 'view' ) {
+ return $this->get_address_prop( 'address_2', 'shipping', $context );
+ }
+
+ /**
+ * Get shipping city.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_shipping_city( $context = 'view' ) {
+ return $this->get_address_prop( 'city', 'shipping', $context );
+ }
+
+ /**
+ * Get shipping state.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_shipping_state( $context = 'view' ) {
+ return $this->get_address_prop( 'state', 'shipping', $context );
+ }
+
+ /**
+ * Get shipping postcode.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_shipping_postcode( $context = 'view' ) {
+ return $this->get_address_prop( 'postcode', 'shipping', $context );
+ }
+
+ /**
+ * Get shipping country.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_shipping_country( $context = 'view' ) {
+ return $this->get_address_prop( 'country', 'shipping', $context );
+ }
+
+ /**
+ * Get the payment method.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_payment_method( $context = 'view' ) {
+ return $this->get_prop( 'payment_method', $context );
+ }
+
+ /**
+ * Get payment method title.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_payment_method_title( $context = 'view' ) {
+ return $this->get_prop( 'payment_method_title', $context );
+ }
+
+ /**
+ * Get transaction d.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_transaction_id( $context = 'view' ) {
+ return $this->get_prop( 'transaction_id', $context );
+ }
+
+ /**
+ * Get customer ip address.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_customer_ip_address( $context = 'view' ) {
+ return $this->get_prop( 'customer_ip_address', $context );
+ }
+
+ /**
+ * Get customer user agent.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_customer_user_agent( $context = 'view' ) {
+ return $this->get_prop( 'customer_user_agent', $context );
+ }
+
+ /**
+ * Get created via.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_created_via( $context = 'view' ) {
+ return $this->get_prop( 'created_via', $context );
+ }
+
+ /**
+ * Get customer note.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_customer_note( $context = 'view' ) {
+ return $this->get_prop( 'customer_note', $context );
+ }
+
+ /**
+ * Get date completed.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return WC_DateTime|NULL object if the date is set or null if there is no date.
+ */
+ public function get_date_completed( $context = 'view' ) {
+ return $this->get_prop( 'date_completed', $context );
+ }
+
+ /**
+ * Get date paid.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return WC_DateTime|NULL object if the date is set or null if there is no date.
+ */
+ public function get_date_paid( $context = 'view' ) {
+ $date_paid = $this->get_prop( 'date_paid', $context );
+
+ if ( 'view' === $context && ! $date_paid && version_compare( $this->get_version( 'edit' ), '3.0', '<' ) && $this->has_status( apply_filters( 'woocommerce_payment_complete_order_status', $this->needs_processing() ? 'processing' : 'completed', $this->get_id(), $this ) ) ) {
+ // In view context, return a date if missing.
+ $date_paid = $this->get_date_created( 'edit' );
+ }
+ return $date_paid;
+ }
+
+ /**
+ * Get cart hash.
+ *
+ * @param string $context What the value is for. Valid values are view and edit.
+ * @return string
+ */
+ public function get_cart_hash( $context = 'view' ) {
+ return $this->get_prop( 'cart_hash', $context );
+ }
+
+ /**
+ * Returns the requested address in raw, non-formatted way.
+ * Note: Merges raw data with get_prop data so changes are returned too.
+ *
+ * @since 2.4.0
+ * @param string $type Billing or shipping. Anything else besides 'billing' will return shipping address.
+ * @return array The stored address after filter.
+ */
+ public function get_address( $type = 'billing' ) {
+ return apply_filters( 'woocommerce_get_order_address', array_merge( $this->data[ $type ], $this->get_prop( $type, 'view' ) ), $type, $this );
+ }
+
+ /**
+ * Get a formatted shipping address for the order.
+ *
+ * @return string
+ */
+ public function get_shipping_address_map_url() {
+ $address = $this->get_address( 'shipping' );
+
+ // Remove name and company before generate the Google Maps URL.
+ unset( $address['first_name'], $address['last_name'], $address['company'] );
+
+ $address = apply_filters( 'woocommerce_shipping_address_map_url_parts', $address, $this );
+
+ return apply_filters( 'woocommerce_shipping_address_map_url', 'https://maps.google.com/maps?&q=' . rawurlencode( implode( ', ', $address ) ) . '&z=16', $this );
+ }
+
+ /**
+ * Get a formatted billing full name.
+ *
+ * @return string
+ */
+ public function get_formatted_billing_full_name() {
+ /* translators: 1: first name 2: last name */
+ return sprintf( _x( '%1$s %2$s', 'full name', 'woocommerce' ), $this->get_billing_first_name(), $this->get_billing_last_name() );
+ }
+
+ /**
+ * Get a formatted shipping full name.
+ *
+ * @return string
+ */
+ public function get_formatted_shipping_full_name() {
+ /* translators: 1: first name 2: last name */
+ return sprintf( _x( '%1$s %2$s', 'full name', 'woocommerce' ), $this->get_shipping_first_name(), $this->get_shipping_last_name() );
+ }
+
+ /**
+ * Get a formatted billing address for the order.
+ *
+ * @param string $empty_content Content to show if no address is present. @since 3.3.0.
+ * @return string
+ */
+ public function get_formatted_billing_address( $empty_content = '' ) {
+ $raw_address = apply_filters( 'woocommerce_order_formatted_billing_address', $this->get_address( 'billing' ), $this );
+ $address = WC()->countries->get_formatted_address( $raw_address );
+
+ /**
+ * Filter orders formatterd billing address.
+ *
+ * @since 3.8.0
+ * @param string $address Formatted billing address string.
+ * @param array $raw_address Raw billing address.
+ * @param WC_Order $order Order data. @since 3.9.0
+ */
+ return apply_filters( 'woocommerce_order_get_formatted_billing_address', $address ? $address : $empty_content, $raw_address, $this );
+ }
+
+ /**
+ * Get a formatted shipping address for the order.
+ *
+ * @param string $empty_content Content to show if no address is present. @since 3.3.0.
+ * @return string
+ */
+ public function get_formatted_shipping_address( $empty_content = '' ) {
+ $address = '';
+ $raw_address = $this->get_address( 'shipping' );
+
+ if ( $this->has_shipping_address() ) {
+ $raw_address = apply_filters( 'woocommerce_order_formatted_shipping_address', $raw_address, $this );
+ $address = WC()->countries->get_formatted_address( $raw_address );
+ }
+
+ /**
+ * Filter orders formatterd shipping address.
+ *
+ * @since 3.8.0
+ * @param string $address Formatted billing address string.
+ * @param array $raw_address Raw billing address.
+ * @param WC_Order $order Order data. @since 3.9.0
+ */
+ return apply_filters( 'woocommerce_order_get_formatted_shipping_address', $address ? $address : $empty_content, $raw_address, $this );
+ }
+
+ /**
+ * Returns true if the order has a billing address.
+ *
+ * @since 3.0.4
+ * @return boolean
+ */
+ public function has_billing_address() {
+ return $this->get_billing_address_1() || $this->get_billing_address_2();
+ }
+
+ /**
+ * Returns true if the order has a shipping address.
+ *
+ * @since 3.0.4
+ * @return boolean
+ */
+ public function has_shipping_address() {
+ return $this->get_shipping_address_1() || $this->get_shipping_address_2();
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Setters
+ |--------------------------------------------------------------------------
+ |
+ | Functions for setting order data. These should not update anything in the
+ | database itself and should only change what is stored in the class
+ | object. However, for backwards compatibility pre 3.0.0 some of these
+ | setters may handle both.
+ |
+ */
+
+ /**
+ * Sets a prop for a setter method.
+ *
+ * @since 3.0.0
+ * @param string $prop Name of prop to set.
+ * @param string $address Name of address to set. billing or shipping.
+ * @param mixed $value Value of the prop.
+ */
+ protected function set_address_prop( $prop, $address, $value ) {
+ if ( array_key_exists( $prop, $this->data[ $address ] ) ) {
+ if ( true === $this->object_read ) {
+ if ( $value !== $this->data[ $address ][ $prop ] || ( isset( $this->changes[ $address ] ) && array_key_exists( $prop, $this->changes[ $address ] ) ) ) {
+ $this->changes[ $address ][ $prop ] = $value;
+ }
+ } else {
+ $this->data[ $address ][ $prop ] = $value;
+ }
+ }
+ }
+
+ /**
+ * Set order key.
+ *
+ * @param string $value Max length 22 chars.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_order_key( $value ) {
+ $this->set_prop( 'order_key', substr( $value, 0, 22 ) );
+ }
+
+ /**
+ * Set customer id.
+ *
+ * @param int $value Customer ID.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_customer_id( $value ) {
+ $this->set_prop( 'customer_id', absint( $value ) );
+ }
+
+ /**
+ * Set billing first name.
+ *
+ * @param string $value Billing first name.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_billing_first_name( $value ) {
+ $this->set_address_prop( 'first_name', 'billing', $value );
+ }
+
+ /**
+ * Set billing last name.
+ *
+ * @param string $value Billing last name.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_billing_last_name( $value ) {
+ $this->set_address_prop( 'last_name', 'billing', $value );
+ }
+
+ /**
+ * Set billing company.
+ *
+ * @param string $value Billing company.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_billing_company( $value ) {
+ $this->set_address_prop( 'company', 'billing', $value );
+ }
+
+ /**
+ * Set billing address line 1.
+ *
+ * @param string $value Billing address line 1.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_billing_address_1( $value ) {
+ $this->set_address_prop( 'address_1', 'billing', $value );
+ }
+
+ /**
+ * Set billing address line 2.
+ *
+ * @param string $value Billing address line 2.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_billing_address_2( $value ) {
+ $this->set_address_prop( 'address_2', 'billing', $value );
+ }
+
+ /**
+ * Set billing city.
+ *
+ * @param string $value Billing city.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_billing_city( $value ) {
+ $this->set_address_prop( 'city', 'billing', $value );
+ }
+
+ /**
+ * Set billing state.
+ *
+ * @param string $value Billing state.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_billing_state( $value ) {
+ $this->set_address_prop( 'state', 'billing', $value );
+ }
+
+ /**
+ * Set billing postcode.
+ *
+ * @param string $value Billing postcode.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_billing_postcode( $value ) {
+ $this->set_address_prop( 'postcode', 'billing', $value );
+ }
+
+ /**
+ * Set billing country.
+ *
+ * @param string $value Billing country.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_billing_country( $value ) {
+ $this->set_address_prop( 'country', 'billing', $value );
+ }
+
+ /**
+ * Maybe set empty billing email to that of the user who owns the order.
+ */
+ protected function maybe_set_user_billing_email() {
+ $user = $this->get_user();
+ if ( ! $this->get_billing_email() && $user ) {
+ try {
+ $this->set_billing_email( $user->user_email );
+ } catch ( WC_Data_Exception $e ) {
+ unset( $e );
+ }
+ }
+ }
+
+ /**
+ * Set billing email.
+ *
+ * @param string $value Billing email.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_billing_email( $value ) {
+ if ( $value && ! is_email( $value ) ) {
+ $this->error( 'order_invalid_billing_email', __( 'Invalid billing email address', 'woocommerce' ) );
+ }
+ $this->set_address_prop( 'email', 'billing', sanitize_email( $value ) );
+ }
+
+ /**
+ * Set billing phone.
+ *
+ * @param string $value Billing phone.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_billing_phone( $value ) {
+ $this->set_address_prop( 'phone', 'billing', $value );
+ }
+
+ /**
+ * Set shipping first name.
+ *
+ * @param string $value Shipping first name.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_shipping_first_name( $value ) {
+ $this->set_address_prop( 'first_name', 'shipping', $value );
+ }
+
+ /**
+ * Set shipping last name.
+ *
+ * @param string $value Shipping last name.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_shipping_last_name( $value ) {
+ $this->set_address_prop( 'last_name', 'shipping', $value );
+ }
+
+ /**
+ * Set shipping company.
+ *
+ * @param string $value Shipping company.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_shipping_company( $value ) {
+ $this->set_address_prop( 'company', 'shipping', $value );
+ }
+
+ /**
+ * Set shipping address line 1.
+ *
+ * @param string $value Shipping address line 1.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_shipping_address_1( $value ) {
+ $this->set_address_prop( 'address_1', 'shipping', $value );
+ }
+
+ /**
+ * Set shipping address line 2.
+ *
+ * @param string $value Shipping address line 2.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_shipping_address_2( $value ) {
+ $this->set_address_prop( 'address_2', 'shipping', $value );
+ }
+
+ /**
+ * Set shipping city.
+ *
+ * @param string $value Shipping city.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_shipping_city( $value ) {
+ $this->set_address_prop( 'city', 'shipping', $value );
+ }
+
+ /**
+ * Set shipping state.
+ *
+ * @param string $value Shipping state.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_shipping_state( $value ) {
+ $this->set_address_prop( 'state', 'shipping', $value );
+ }
+
+ /**
+ * Set shipping postcode.
+ *
+ * @param string $value Shipping postcode.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_shipping_postcode( $value ) {
+ $this->set_address_prop( 'postcode', 'shipping', $value );
+ }
+
+ /**
+ * Set shipping country.
+ *
+ * @param string $value Shipping country.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_shipping_country( $value ) {
+ $this->set_address_prop( 'country', 'shipping', $value );
+ }
+
+ /**
+ * Set the payment method.
+ *
+ * @param string $payment_method Supports WC_Payment_Gateway for bw compatibility with < 3.0.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_payment_method( $payment_method = '' ) {
+ if ( is_object( $payment_method ) ) {
+ $this->set_payment_method( $payment_method->id );
+ $this->set_payment_method_title( $payment_method->get_title() );
+ } elseif ( '' === $payment_method ) {
+ $this->set_prop( 'payment_method', '' );
+ $this->set_prop( 'payment_method_title', '' );
+ } else {
+ $this->set_prop( 'payment_method', $payment_method );
+ }
+ }
+
+ /**
+ * Set payment method title.
+ *
+ * @param string $value Payment method title.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_payment_method_title( $value ) {
+ $this->set_prop( 'payment_method_title', $value );
+ }
+
+ /**
+ * Set transaction id.
+ *
+ * @param string $value Transaction id.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_transaction_id( $value ) {
+ $this->set_prop( 'transaction_id', $value );
+ }
+
+ /**
+ * Set customer ip address.
+ *
+ * @param string $value Customer ip address.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_customer_ip_address( $value ) {
+ $this->set_prop( 'customer_ip_address', $value );
+ }
+
+ /**
+ * Set customer user agent.
+ *
+ * @param string $value Customer user agent.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_customer_user_agent( $value ) {
+ $this->set_prop( 'customer_user_agent', $value );
+ }
+
+ /**
+ * Set created via.
+ *
+ * @param string $value Created via.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_created_via( $value ) {
+ $this->set_prop( 'created_via', $value );
+ }
+
+ /**
+ * Set customer note.
+ *
+ * @param string $value Customer note.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_customer_note( $value ) {
+ $this->set_prop( 'customer_note', $value );
+ }
+
+ /**
+ * Set date completed.
+ *
+ * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_date_completed( $date = null ) {
+ $this->set_date_prop( 'date_completed', $date );
+ }
+
+ /**
+ * Set date paid.
+ *
+ * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_date_paid( $date = null ) {
+ $this->set_date_prop( 'date_paid', $date );
+ }
+
+ /**
+ * Set cart hash.
+ *
+ * @param string $value Cart hash.
+ * @throws WC_Data_Exception Throws exception when invalid data is found.
+ */
+ public function set_cart_hash( $value ) {
+ $this->set_prop( 'cart_hash', $value );
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Conditionals
+ |--------------------------------------------------------------------------
+ |
+ | Checks if a condition is true or false.
+ |
+ */
+
+ /**
+ * Check if an order key is valid.
+ *
+ * @param string $key Order key.
+ * @return bool
+ */
+ public function key_is_valid( $key ) {
+ return hash_equals( $this->get_order_key(), $key );
+ }
+
+ /**
+ * See if order matches cart_hash.
+ *
+ * @param string $cart_hash Cart hash.
+ * @return bool
+ */
+ public function has_cart_hash( $cart_hash = '' ) {
+ return hash_equals( $this->get_cart_hash(), $cart_hash ); // @codingStandardsIgnoreLine
+ }
+
+ /**
+ * Checks if an order can be edited, specifically for use on the Edit Order screen.
+ *
+ * @return bool
+ */
+ public function is_editable() {
+ return apply_filters( 'wc_order_is_editable', in_array( $this->get_status(), array( 'pending', 'on-hold', 'auto-draft' ), true ), $this );
+ }
+
+ /**
+ * Returns if an order has been paid for based on the order status.
+ *
+ * @since 2.5.0
+ * @return bool
+ */
+ public function is_paid() {
+ return apply_filters( 'woocommerce_order_is_paid', $this->has_status( wc_get_is_paid_statuses() ), $this );
+ }
+
+ /**
+ * Checks if product download is permitted.
+ *
+ * @return bool
+ */
+ public function is_download_permitted() {
+ return apply_filters( 'woocommerce_order_is_download_permitted', $this->has_status( 'completed' ) || ( 'yes' === get_option( 'woocommerce_downloads_grant_access_after_payment' ) && $this->has_status( 'processing' ) ), $this );
+ }
+
+ /**
+ * Checks if an order needs display the shipping address, based on shipping method.
+ *
+ * @return bool
+ */
+ public function needs_shipping_address() {
+ if ( 'no' === get_option( 'woocommerce_calc_shipping' ) ) {
+ return false;
+ }
+
+ $hide = apply_filters( 'woocommerce_order_hide_shipping_address', array( 'local_pickup' ), $this );
+ $needs_address = false;
+
+ foreach ( $this->get_shipping_methods() as $shipping_method ) {
+ $shipping_method_id = $shipping_method->get_method_id();
+
+ if ( ! in_array( $shipping_method_id, $hide, true ) ) {
+ $needs_address = true;
+ break;
+ }
+ }
+
+ return apply_filters( 'woocommerce_order_needs_shipping_address', $needs_address, $hide, $this );
+ }
+
+ /**
+ * Returns true if the order contains a downloadable product.
+ *
+ * @return bool
+ */
+ public function has_downloadable_item() {
+ foreach ( $this->get_items() as $item ) {
+ if ( $item->is_type( 'line_item' ) ) {
+ $product = $item->get_product();
+
+ if ( $product && $product->has_file() ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get downloads from all line items for this order.
+ *
+ * @since 3.2.0
+ * @return array
+ */
+ public function get_downloadable_items() {
+ $downloads = array();
+
+ foreach ( $this->get_items() as $item ) {
+ if ( ! is_object( $item ) ) {
+ continue;
+ }
+
+ // Check item refunds.
+ $refunded_qty = abs( $this->get_qty_refunded_for_item( $item->get_id() ) );
+ if ( $refunded_qty && $item->get_quantity() === $refunded_qty ) {
+ continue;
+ }
+
+ if ( $item->is_type( 'line_item' ) ) {
+ $item_downloads = $item->get_item_downloads();
+ $product = $item->get_product();
+ if ( $product && $item_downloads ) {
+ foreach ( $item_downloads as $file ) {
+ $downloads[] = array(
+ 'download_url' => $file['download_url'],
+ 'download_id' => $file['id'],
+ 'product_id' => $product->get_id(),
+ 'product_name' => $product->get_name(),
+ 'product_url' => $product->is_visible() ? $product->get_permalink() : '', // Since 3.3.0.
+ 'download_name' => $file['name'],
+ 'order_id' => $this->get_id(),
+ 'order_key' => $this->get_order_key(),
+ 'downloads_remaining' => $file['downloads_remaining'],
+ 'access_expires' => $file['access_expires'],
+ 'file' => array(
+ 'name' => $file['name'],
+ 'file' => $file['file'],
+ ),
+ );
+ }
+ }
+ }
+ }
+
+ return apply_filters( 'woocommerce_order_get_downloadable_items', $downloads, $this );
+ }
+
+ /**
+ * Checks if an order needs payment, based on status and order total.
+ *
+ * @return bool
+ */
+ public function needs_payment() {
+ $valid_order_statuses = apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'failed' ), $this );
+ return apply_filters( 'woocommerce_order_needs_payment', ( $this->has_status( $valid_order_statuses ) && $this->get_total() > 0 ), $this, $valid_order_statuses );
+ }
+
+ /**
+ * See if the order needs processing before it can be completed.
+ *
+ * Orders which only contain virtual, downloadable items do not need admin
+ * intervention.
+ *
+ * Uses a transient so these calls are not repeated multiple times, and because
+ * once the order is processed this code/transient does not need to persist.
+ *
+ * @since 3.0.0
+ * @return bool
+ */
+ public function needs_processing() {
+ $transient_name = 'wc_order_' . $this->get_id() . '_needs_processing';
+ $needs_processing = get_transient( $transient_name );
+
+ if ( false === $needs_processing ) {
+ $needs_processing = 0;
+
+ if ( count( $this->get_items() ) > 0 ) {
+ foreach ( $this->get_items() as $item ) {
+ if ( $item->is_type( 'line_item' ) ) {
+ $product = $item->get_product();
+
+ if ( ! $product ) {
+ continue;
+ }
+
+ $virtual_downloadable_item = $product->is_downloadable() && $product->is_virtual();
+
+ if ( apply_filters( 'woocommerce_order_item_needs_processing', ! $virtual_downloadable_item, $product, $this->get_id() ) ) {
+ $needs_processing = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ set_transient( $transient_name, $needs_processing, DAY_IN_SECONDS );
+ }
+
+ return 1 === absint( $needs_processing );
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | URLs and Endpoints
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Generates a URL so that a customer can pay for their (unpaid - pending) order. Pass 'true' for the checkout version which doesn't offer gateway choices.
+ *
+ * @param bool $on_checkout If on checkout.
+ * @return string
+ */
+ public function get_checkout_payment_url( $on_checkout = false ) {
+ $pay_url = wc_get_endpoint_url( 'order-pay', $this->get_id(), wc_get_checkout_url() );
+
+ if ( $on_checkout ) {
+ $pay_url = add_query_arg( 'key', $this->get_order_key(), $pay_url );
+ } else {
+ $pay_url = add_query_arg(
+ array(
+ 'pay_for_order' => 'true',
+ 'key' => $this->get_order_key(),
+ ),
+ $pay_url
+ );
+ }
+
+ return apply_filters( 'woocommerce_get_checkout_payment_url', $pay_url, $this );
+ }
+
+ /**
+ * Generates a URL for the thanks page (order received).
+ *
+ * @return string
+ */
+ public function get_checkout_order_received_url() {
+ $order_received_url = wc_get_endpoint_url( 'order-received', $this->get_id(), wc_get_checkout_url() );
+ $order_received_url = add_query_arg( 'key', $this->get_order_key(), $order_received_url );
+
+ return apply_filters( 'woocommerce_get_checkout_order_received_url', $order_received_url, $this );
+ }
+
+ /**
+ * Generates a URL so that a customer can cancel their (unpaid - pending) order.
+ *
+ * @param string $redirect Redirect URL.
+ * @return string
+ */
+ public function get_cancel_order_url( $redirect = '' ) {
+ return apply_filters(
+ 'woocommerce_get_cancel_order_url',
+ wp_nonce_url(
+ add_query_arg(
+ array(
+ 'cancel_order' => 'true',
+ 'order' => $this->get_order_key(),
+ 'order_id' => $this->get_id(),
+ 'redirect' => $redirect,
+ ),
+ $this->get_cancel_endpoint()
+ ),
+ 'woocommerce-cancel_order'
+ )
+ );
+ }
+
+ /**
+ * Generates a raw (unescaped) cancel-order URL for use by payment gateways.
+ *
+ * @param string $redirect Redirect URL.
+ * @return string The unescaped cancel-order URL.
+ */
+ public function get_cancel_order_url_raw( $redirect = '' ) {
+ return apply_filters(
+ 'woocommerce_get_cancel_order_url_raw',
+ add_query_arg(
+ array(
+ 'cancel_order' => 'true',
+ 'order' => $this->get_order_key(),
+ 'order_id' => $this->get_id(),
+ 'redirect' => $redirect,
+ '_wpnonce' => wp_create_nonce( 'woocommerce-cancel_order' ),
+ ),
+ $this->get_cancel_endpoint()
+ )
+ );
+ }
+
+ /**
+ * Helper method to return the cancel endpoint.
+ *
+ * @return string the cancel endpoint; either the cart page or the home page.
+ */
+ public function get_cancel_endpoint() {
+ $cancel_endpoint = wc_get_cart_url();
+ if ( ! $cancel_endpoint ) {
+ $cancel_endpoint = home_url();
+ }
+
+ if ( false === strpos( $cancel_endpoint, '?' ) ) {
+ $cancel_endpoint = trailingslashit( $cancel_endpoint );
+ }
+
+ return $cancel_endpoint;
+ }
+
+ /**
+ * Generates a URL to view an order from the my account page.
+ *
+ * @return string
+ */
+ public function get_view_order_url() {
+ return apply_filters( 'woocommerce_get_view_order_url', wc_get_endpoint_url( 'view-order', $this->get_id(), wc_get_page_permalink( 'myaccount' ) ), $this );
+ }
+
+ /**
+ * Get's the URL to edit the order in the backend.
+ *
+ * @since 3.3.0
+ * @return string
+ */
+ public function get_edit_order_url() {
+ return apply_filters( 'woocommerce_get_edit_order_url', get_admin_url( null, 'post.php?post=' . $this->get_id() . '&action=edit' ), $this );
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Order notes.
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Adds a note (comment) to the order. Order must exist.
+ *
+ * @param string $note Note to add.
+ * @param int $is_customer_note Is this a note for the customer?.
+ * @param bool $added_by_user Was the note added by a user?.
+ * @return int Comment ID.
+ */
+ public function add_order_note( $note, $is_customer_note = 0, $added_by_user = false ) {
+ if ( ! $this->get_id() ) {
+ return 0;
+ }
+
+ if ( is_user_logged_in() && current_user_can( 'edit_shop_orders', $this->get_id() ) && $added_by_user ) {
+ $user = get_user_by( 'id', get_current_user_id() );
+ $comment_author = $user->display_name;
+ $comment_author_email = $user->user_email;
+ } else {
+ $comment_author = __( 'WooCommerce', 'woocommerce' );
+ $comment_author_email = strtolower( __( 'WooCommerce', 'woocommerce' ) ) . '@';
+ $comment_author_email .= isset( $_SERVER['HTTP_HOST'] ) ? str_replace( 'www.', '', sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) ) ) : 'noreply.com'; // WPCS: input var ok.
+ $comment_author_email = sanitize_email( $comment_author_email );
+ }
+ $commentdata = apply_filters(
+ 'woocommerce_new_order_note_data',
+ array(
+ 'comment_post_ID' => $this->get_id(),
+ 'comment_author' => $comment_author,
+ 'comment_author_email' => $comment_author_email,
+ 'comment_author_url' => '',
+ 'comment_content' => $note,
+ 'comment_agent' => 'WooCommerce',
+ 'comment_type' => 'order_note',
+ 'comment_parent' => 0,
+ 'comment_approved' => 1,
+ ),
+ array(
+ 'order_id' => $this->get_id(),
+ 'is_customer_note' => $is_customer_note,
+ )
+ );
+
+ $comment_id = wp_insert_comment( $commentdata );
+
+ if ( $is_customer_note ) {
+ add_comment_meta( $comment_id, 'is_customer_note', 1 );
+
+ do_action(
+ 'woocommerce_new_customer_note',
+ array(
+ 'order_id' => $this->get_id(),
+ 'customer_note' => $commentdata['comment_content'],
+ )
+ );
+ }
+
+ /**
+ * Action hook fired after an order note is added.
+ *
+ * @param int $order_note_id Order note ID.
+ * @param WC_Order $order Order data.
+ *
+ * @since 4.4.0
+ */
+ do_action( 'woocommerce_order_note_added', $comment_id, $this );
+
+ return $comment_id;
+ }
+
+ /**
+ * Add an order note for status transition
+ *
+ * @since 3.9.0
+ * @uses WC_Order::add_order_note()
+ * @param string $note Note to be added giving status transition from and to details.
+ * @param bool $transition Details of the status transition.
+ * @return int Comment ID.
+ */
+ private function add_status_transition_note( $note, $transition ) {
+ return $this->add_order_note( trim( $transition['note'] . ' ' . $note ), 0, $transition['manual'] );
+ }
+
+ /**
+ * List order notes (public) for the customer.
+ *
+ * @return array
+ */
+ public function get_customer_order_notes() {
+ $notes = array();
+ $args = array(
+ 'post_id' => $this->get_id(),
+ 'approve' => 'approve',
+ 'type' => '',
+ );
+
+ remove_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ) );
+
+ $comments = get_comments( $args );
+
+ foreach ( $comments as $comment ) {
+ if ( ! get_comment_meta( $comment->comment_ID, 'is_customer_note', true ) ) {
+ continue;
+ }
+ $comment->comment_content = make_clickable( $comment->comment_content );
+ $notes[] = $comment;
+ }
+
+ add_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ) );
+
+ return $notes;
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Refunds
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Get order refunds.
+ *
+ * @since 2.2
+ * @return array of WC_Order_Refund objects
+ */
+ public function get_refunds() {
+ $cache_key = WC_Cache_Helper::get_cache_prefix( 'orders' ) . 'refunds' . $this->get_id();
+ $cached_data = wp_cache_get( $cache_key, $this->cache_group );
+
+ if ( false !== $cached_data ) {
+ return $cached_data;
+ }
+
+ $this->refunds = wc_get_orders(
+ array(
+ 'type' => 'shop_order_refund',
+ 'parent' => $this->get_id(),
+ 'limit' => -1,
+ )
+ );
+
+ wp_cache_set( $cache_key, $this->refunds, $this->cache_group );
+
+ return $this->refunds;
+ }
+
+ /**
+ * Get amount already refunded.
+ *
+ * @since 2.2
+ * @return string
+ */
+ public function get_total_refunded() {
+ $cache_key = WC_Cache_Helper::get_cache_prefix( 'orders' ) . 'total_refunded' . $this->get_id();
+ $cached_data = wp_cache_get( $cache_key, $this->cache_group );
+
+ if ( false !== $cached_data ) {
+ return $cached_data;
+ }
+
+ $total_refunded = $this->data_store->get_total_refunded( $this );
+
+ wp_cache_set( $cache_key, $total_refunded, $this->cache_group );
+
+ return $total_refunded;
+ }
+
+ /**
+ * Get the total tax refunded.
+ *
+ * @since 2.3
+ * @return float
+ */
+ public function get_total_tax_refunded() {
+ $cache_key = WC_Cache_Helper::get_cache_prefix( 'orders' ) . 'total_tax_refunded' . $this->get_id();
+ $cached_data = wp_cache_get( $cache_key, $this->cache_group );
+
+ if ( false !== $cached_data ) {
+ return $cached_data;
+ }
+
+ $total_refunded = $this->data_store->get_total_tax_refunded( $this );
+
+ wp_cache_set( $cache_key, $total_refunded, $this->cache_group );
+
+ return $total_refunded;
+ }
+
+ /**
+ * Get the total shipping refunded.
+ *
+ * @since 2.4
+ * @return float
+ */
+ public function get_total_shipping_refunded() {
+ $cache_key = WC_Cache_Helper::get_cache_prefix( 'orders' ) . 'total_shipping_refunded' . $this->get_id();
+ $cached_data = wp_cache_get( $cache_key, $this->cache_group );
+
+ if ( false !== $cached_data ) {
+ return $cached_data;
+ }
+
+ $total_refunded = $this->data_store->get_total_shipping_refunded( $this );
+
+ wp_cache_set( $cache_key, $total_refunded, $this->cache_group );
+
+ return $total_refunded;
+ }
+
+ /**
+ * Gets the count of order items of a certain type that have been refunded.
+ *
+ * @since 2.4.0
+ * @param string $item_type Item type.
+ * @return string
+ */
+ public function get_item_count_refunded( $item_type = '' ) {
+ if ( empty( $item_type ) ) {
+ $item_type = array( 'line_item' );
+ }
+ if ( ! is_array( $item_type ) ) {
+ $item_type = array( $item_type );
+ }
+ $count = 0;
+
+ foreach ( $this->get_refunds() as $refund ) {
+ foreach ( $refund->get_items( $item_type ) as $refunded_item ) {
+ $count += abs( $refunded_item->get_quantity() );
+ }
+ }
+
+ return apply_filters( 'woocommerce_get_item_count_refunded', $count, $item_type, $this );
+ }
+
+ /**
+ * Get the total number of items refunded.
+ *
+ * @since 2.4.0
+ *
+ * @param string $item_type Type of the item we're checking, if not a line_item.
+ * @return int
+ */
+ public function get_total_qty_refunded( $item_type = 'line_item' ) {
+ $qty = 0;
+ foreach ( $this->get_refunds() as $refund ) {
+ foreach ( $refund->get_items( $item_type ) as $refunded_item ) {
+ $qty += $refunded_item->get_quantity();
+ }
+ }
+ return $qty;
+ }
+
+ /**
+ * Get the refunded amount for a line item.
+ *
+ * @param int $item_id ID of the item we're checking.
+ * @param string $item_type Type of the item we're checking, if not a line_item.
+ * @return int
+ */
+ public function get_qty_refunded_for_item( $item_id, $item_type = 'line_item' ) {
+ $qty = 0;
+ foreach ( $this->get_refunds() as $refund ) {
+ foreach ( $refund->get_items( $item_type ) as $refunded_item ) {
+ if ( absint( $refunded_item->get_meta( '_refunded_item_id' ) ) === $item_id ) {
+ $qty += $refunded_item->get_quantity();
+ }
+ }
+ }
+ return $qty;
+ }
+
+ /**
+ * Get the refunded amount for a line item.
+ *
+ * @param int $item_id ID of the item we're checking.
+ * @param string $item_type Type of the item we're checking, if not a line_item.
+ * @return int
+ */
+ public function get_total_refunded_for_item( $item_id, $item_type = 'line_item' ) {
+ $total = 0;
+ foreach ( $this->get_refunds() as $refund ) {
+ foreach ( $refund->get_items( $item_type ) as $refunded_item ) {
+ if ( absint( $refunded_item->get_meta( '_refunded_item_id' ) ) === $item_id ) {
+ $total += $refunded_item->get_total();
+ }
+ }
+ }
+ return $total * -1;
+ }
+
+ /**
+ * Get the refunded tax amount for a line item.
+ *
+ * @param int $item_id ID of the item we're checking.
+ * @param int $tax_id ID of the tax we're checking.
+ * @param string $item_type Type of the item we're checking, if not a line_item.
+ * @return double
+ */
+ public function get_tax_refunded_for_item( $item_id, $tax_id, $item_type = 'line_item' ) {
+ $total = 0;
+ foreach ( $this->get_refunds() as $refund ) {
+ foreach ( $refund->get_items( $item_type ) as $refunded_item ) {
+ $refunded_item_id = (int) $refunded_item->get_meta( '_refunded_item_id' );
+ if ( $refunded_item_id === $item_id ) {
+ $taxes = $refunded_item->get_taxes();
+ $total += isset( $taxes['total'][ $tax_id ] ) ? (float) $taxes['total'][ $tax_id ] : 0;
+ break;
+ }
+ }
+ }
+ return wc_round_tax_total( $total ) * -1;
+ }
+
+ /**
+ * Get total tax refunded by rate ID.
+ *
+ * @param int $rate_id Rate ID.
+ * @return float
+ */
+ public function get_total_tax_refunded_by_rate_id( $rate_id ) {
+ $total = 0;
+ foreach ( $this->get_refunds() as $refund ) {
+ foreach ( $refund->get_items( 'tax' ) as $refunded_item ) {
+ if ( absint( $refunded_item->get_rate_id() ) === $rate_id ) {
+ $total += abs( $refunded_item->get_tax_total() ) + abs( $refunded_item->get_shipping_tax_total() );
+ }
+ }
+ }
+
+ return $total;
+ }
+
+ /**
+ * How much money is left to refund?
+ *
+ * @return string
+ */
+ public function get_remaining_refund_amount() {
+ return wc_format_decimal( $this->get_total() - $this->get_total_refunded(), wc_get_price_decimals() );
+ }
+
+ /**
+ * How many items are left to refund?
+ *
+ * @return int
+ */
+ public function get_remaining_refund_items() {
+ return absint( $this->get_item_count() - $this->get_item_count_refunded() );
+ }
+
+ /**
+ * Add total row for the payment method.
+ *
+ * @param array $total_rows Total rows.
+ * @param string $tax_display Tax to display.
+ */
+ protected function add_order_item_totals_payment_method_row( &$total_rows, $tax_display ) {
+ if ( $this->get_total() > 0 && $this->get_payment_method_title() && 'other' !== $this->get_payment_method_title() ) {
+ $total_rows['payment_method'] = array(
+ 'label' => __( 'Payment method:', 'woocommerce' ),
+ 'value' => $this->get_payment_method_title(),
+ );
+ }
+ }
+
+ /**
+ * Add total row for refunds.
+ *
+ * @param array $total_rows Total rows.
+ * @param string $tax_display Tax to display.
+ */
+ protected function add_order_item_totals_refund_rows( &$total_rows, $tax_display ) {
+ $refunds = $this->get_refunds();
+ if ( $refunds ) {
+ foreach ( $refunds as $id => $refund ) {
+ $total_rows[ 'refund_' . $id ] = array(
+ 'label' => $refund->get_reason() ? $refund->get_reason() : __( 'Refund', 'woocommerce' ) . ':',
+ 'value' => wc_price( '-' . $refund->get_amount(), array( 'currency' => $this->get_currency() ) ),
+ );
+ }
+ }
+ }
+
+ /**
+ * Get totals for display on pages and in emails.
+ *
+ * @param string $tax_display Tax to display.
+ * @return array
+ */
+ public function get_order_item_totals( $tax_display = '' ) {
+ $tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' );
+ $total_rows = array();
+
+ $this->add_order_item_totals_subtotal_row( $total_rows, $tax_display );
+ $this->add_order_item_totals_discount_row( $total_rows, $tax_display );
+ $this->add_order_item_totals_shipping_row( $total_rows, $tax_display );
+ $this->add_order_item_totals_fee_rows( $total_rows, $tax_display );
+ $this->add_order_item_totals_tax_rows( $total_rows, $tax_display );
+ $this->add_order_item_totals_payment_method_row( $total_rows, $tax_display );
+ $this->add_order_item_totals_refund_rows( $total_rows, $tax_display );
+ $this->add_order_item_totals_total_row( $total_rows, $tax_display );
+
+ return apply_filters( 'woocommerce_get_order_item_totals', $total_rows, $this, $tax_display );
+ }
+
+ /**
+ * Check if order has been created via admin, checkout, or in another way.
+ *
+ * @since 4.0.0
+ * @param string $modus Way of creating the order to test for.
+ * @return bool
+ */
+ public function is_created_via( $modus ) {
+ return apply_filters( 'woocommerce_order_is_created_via', $modus === $this->get_created_via(), $this, $modus );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-payment-gateways.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-payment-gateways.php
new file mode 100644
index 0000000..c6114ef
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-payment-gateways.php
@@ -0,0 +1,222 @@
+init();
+ }
+
+ /**
+ * Load gateways and hook in functions.
+ */
+ public function init() {
+ $load_gateways = array(
+ 'WC_Gateway_BACS',
+ 'WC_Gateway_Cheque',
+ 'WC_Gateway_COD',
+ 'WC_Gateway_Paypal',
+ );
+
+ // Filter.
+ $load_gateways = apply_filters( 'woocommerce_payment_gateways', $load_gateways );
+
+ // Get sort order option.
+ $ordering = (array) get_option( 'woocommerce_gateway_order' );
+ $order_end = 999;
+
+ // Load gateways in order.
+ foreach ( $load_gateways as $gateway ) {
+ if ( is_string( $gateway ) && class_exists( $gateway ) ) {
+ $gateway = new $gateway();
+ }
+
+ // Gateways need to be valid and extend WC_Payment_Gateway.
+ if ( ! is_a( $gateway, 'WC_Payment_Gateway' ) ) {
+ continue;
+ }
+
+ if ( isset( $ordering[ $gateway->id ] ) && is_numeric( $ordering[ $gateway->id ] ) ) {
+ // Add in position.
+ $this->payment_gateways[ $ordering[ $gateway->id ] ] = $gateway;
+ } else {
+ // Add to end of the array.
+ $this->payment_gateways[ $order_end ] = $gateway;
+ $order_end++;
+ }
+ }
+
+ ksort( $this->payment_gateways );
+ }
+
+ /**
+ * Get gateways.
+ *
+ * @return array
+ */
+ public function payment_gateways() {
+ $_available_gateways = array();
+
+ if ( count( $this->payment_gateways ) > 0 ) {
+ foreach ( $this->payment_gateways as $gateway ) {
+ $_available_gateways[ $gateway->id ] = $gateway;
+ }
+ }
+
+ return $_available_gateways;
+ }
+
+ /**
+ * Get array of registered gateway ids
+ *
+ * @since 2.6.0
+ * @return array of strings
+ */
+ public function get_payment_gateway_ids() {
+ return wp_list_pluck( $this->payment_gateways, 'id' );
+ }
+
+ /**
+ * Get available gateways.
+ *
+ * @return array
+ */
+ public function get_available_payment_gateways() {
+ $_available_gateways = array();
+
+ foreach ( $this->payment_gateways as $gateway ) {
+ if ( $gateway->is_available() ) {
+ if ( ! is_add_payment_method_page() ) {
+ $_available_gateways[ $gateway->id ] = $gateway;
+ } elseif ( $gateway->supports( 'add_payment_method' ) || $gateway->supports( 'tokenization' ) ) {
+ $_available_gateways[ $gateway->id ] = $gateway;
+ }
+ }
+ }
+
+ return array_filter( (array) apply_filters( 'woocommerce_available_payment_gateways', $_available_gateways ), array( $this, 'filter_valid_gateway_class' ) );
+ }
+
+ /**
+ * Callback for array filter. Returns true if gateway is of correct type.
+ *
+ * @since 3.6.0
+ * @param object $gateway Gateway to check.
+ * @return bool
+ */
+ protected function filter_valid_gateway_class( $gateway ) {
+ return $gateway && is_a( $gateway, 'WC_Payment_Gateway' );
+ }
+
+ /**
+ * Set the current, active gateway.
+ *
+ * @param array $gateways Available payment gateways.
+ */
+ public function set_current_gateway( $gateways ) {
+ // Be on the defensive.
+ if ( ! is_array( $gateways ) || empty( $gateways ) ) {
+ return;
+ }
+
+ $current_gateway = false;
+
+ if ( WC()->session ) {
+ $current = WC()->session->get( 'chosen_payment_method' );
+
+ if ( $current && isset( $gateways[ $current ] ) ) {
+ $current_gateway = $gateways[ $current ];
+ }
+ }
+
+ if ( ! $current_gateway ) {
+ $current_gateway = current( $gateways );
+ }
+
+ // Ensure we can make a call to set_current() without triggering an error.
+ if ( $current_gateway && is_callable( array( $current_gateway, 'set_current' ) ) ) {
+ $current_gateway->set_current();
+ }
+ }
+
+ /**
+ * Save options in admin.
+ */
+ public function process_admin_options() {
+ $gateway_order = isset( $_POST['gateway_order'] ) ? wc_clean( wp_unslash( $_POST['gateway_order'] ) ) : ''; // WPCS: input var ok, CSRF ok.
+ $order = array();
+
+ if ( is_array( $gateway_order ) && count( $gateway_order ) > 0 ) {
+ $loop = 0;
+ foreach ( $gateway_order as $gateway_id ) {
+ $order[ esc_attr( $gateway_id ) ] = $loop;
+ $loop++;
+ }
+ }
+
+ update_option( 'woocommerce_gateway_order', $order );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-payment-tokens.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-payment-tokens.php
new file mode 100644
index 0000000..85625d0
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-payment-tokens.php
@@ -0,0 +1,234 @@
+ '',
+ 'user_id' => '',
+ 'gateway_id' => '',
+ 'type' => '',
+ )
+ );
+
+ $data_store = WC_Data_Store::load( 'payment-token' );
+ $token_results = $data_store->get_tokens( $args );
+ $tokens = array();
+
+ if ( ! empty( $token_results ) ) {
+ foreach ( $token_results as $token_result ) {
+ $_token = self::get( $token_result->token_id, $token_result );
+ if ( ! empty( $_token ) ) {
+ $tokens[ $token_result->token_id ] = $_token;
+ }
+ }
+ }
+
+ return $tokens;
+ }
+
+ /**
+ * Returns an array of payment token objects associated with the passed customer ID.
+ *
+ * @since 2.6.0
+ * @param int $customer_id Customer ID.
+ * @param string $gateway_id Optional Gateway ID for getting tokens for a specific gateway.
+ * @return WC_Payment_Token[] Array of token objects.
+ */
+ public static function get_customer_tokens( $customer_id, $gateway_id = '' ) {
+ if ( $customer_id < 1 ) {
+ return array();
+ }
+
+ $tokens = self::get_tokens(
+ array(
+ 'user_id' => $customer_id,
+ 'gateway_id' => $gateway_id,
+ )
+ );
+
+ return apply_filters( 'woocommerce_get_customer_payment_tokens', $tokens, $customer_id, $gateway_id );
+ }
+
+ /**
+ * Returns a customers default token or NULL if there is no default token.
+ *
+ * @since 2.6.0
+ * @param int $customer_id Customer ID.
+ * @return WC_Payment_Token|null
+ */
+ public static function get_customer_default_token( $customer_id ) {
+ if ( $customer_id < 1 ) {
+ return null;
+ }
+
+ $data_store = WC_Data_Store::load( 'payment-token' );
+ $token = $data_store->get_users_default_token( $customer_id );
+
+ if ( $token ) {
+ return self::get( $token->token_id, $token );
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns an array of payment token objects associated with the passed order ID.
+ *
+ * @since 2.6.0
+ * @param int $order_id Order ID.
+ * @return WC_Payment_Token[] Array of token objects.
+ */
+ public static function get_order_tokens( $order_id ) {
+ $order = wc_get_order( $order_id );
+
+ if ( ! $order ) {
+ return array();
+ }
+
+ $token_ids = $order->get_payment_tokens();
+
+ if ( empty( $token_ids ) ) {
+ return array();
+ }
+
+ $tokens = self::get_tokens(
+ array(
+ 'token_id' => $token_ids,
+ )
+ );
+
+ return apply_filters( 'woocommerce_get_order_payment_tokens', $tokens, $order_id );
+ }
+
+ /**
+ * Get a token object by ID.
+ *
+ * @since 2.6.0
+ *
+ * @param int $token_id Token ID.
+ * @param object $token_result Token result.
+ * @return null|WC_Payment_Token Returns a valid payment token or null if no token can be found.
+ */
+ public static function get( $token_id, $token_result = null ) {
+ $data_store = WC_Data_Store::load( 'payment-token' );
+
+ if ( is_null( $token_result ) ) {
+ $token_result = $data_store->get_token_by_id( $token_id );
+ // Still empty? Token doesn't exist? Don't continue.
+ if ( empty( $token_result ) ) {
+ return null;
+ }
+ }
+
+ $token_class = self::get_token_classname( $token_result->type );
+
+ if ( class_exists( $token_class ) ) {
+ $meta = $data_store->get_metadata( $token_id );
+ $passed_meta = array();
+ if ( ! empty( $meta ) ) {
+ foreach ( $meta as $meta_key => $meta_value ) {
+ $passed_meta[ $meta_key ] = $meta_value[0];
+ }
+ }
+ return new $token_class( $token_id, (array) $token_result, $passed_meta );
+ }
+
+ return null;
+ }
+
+ /**
+ * Remove a payment token from the database by ID.
+ *
+ * @since 2.6.0
+ * @param int $token_id Token ID.
+ */
+ public static function delete( $token_id ) {
+ $type = self::get_token_type_by_id( $token_id );
+ if ( ! empty( $type ) ) {
+ $class = self::get_token_classname( $type );
+ $token = new $class( $token_id );
+ $token->delete();
+ }
+ }
+
+ /**
+ * Loops through all of a users payment tokens and sets is_default to false for all but a specific token.
+ *
+ * @since 2.6.0
+ * @param int $user_id User to set a default for.
+ * @param int $token_id The ID of the token that should be default.
+ */
+ public static function set_users_default( $user_id, $token_id ) {
+ $data_store = WC_Data_Store::load( 'payment-token' );
+ $users_tokens = self::get_customer_tokens( $user_id );
+ foreach ( $users_tokens as $token ) {
+ if ( $token_id === $token->get_id() ) {
+ $data_store->set_default_status( $token->get_id(), true );
+ do_action( 'woocommerce_payment_token_set_default', $token_id, $token );
+ } else {
+ $data_store->set_default_status( $token->get_id(), false );
+ }
+ }
+ }
+
+ /**
+ * Returns what type (credit card, echeck, etc) of token a token is by ID.
+ *
+ * @since 2.6.0
+ * @param int $token_id Token ID.
+ * @return string Type.
+ */
+ public static function get_token_type_by_id( $token_id ) {
+ $data_store = WC_Data_Store::load( 'payment-token' );
+ return $data_store->get_token_type_by_id( $token_id );
+ }
+
+ /**
+ * Get classname based on token type.
+ *
+ * @since 3.8.0
+ * @param string $type Token type.
+ * @return string
+ */
+ protected static function get_token_classname( $type ) {
+ /**
+ * Filter payment token class per type.
+ *
+ * @since 3.8.0
+ * @param string $class Payment token class.
+ * @param string $type Token type.
+ */
+ return apply_filters( 'woocommerce_payment_token_class', 'WC_Payment_Token_' . $type, $type );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-post-data.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-post-data.php
new file mode 100644
index 0000000..39b89ba
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-post-data.php
@@ -0,0 +1,533 @@
+ID, $post->post_type ) && 'product_variation' === $post->post_type ) {
+ $variation = wc_get_product( $post->ID );
+
+ if ( $variation && $variation->get_parent_id() ) {
+ return $variation->get_permalink();
+ }
+ }
+ return $permalink;
+ }
+
+ /**
+ * Sync products queued to sync.
+ */
+ public static function do_deferred_product_sync() {
+ global $wc_deferred_product_sync;
+
+ if ( ! empty( $wc_deferred_product_sync ) ) {
+ $wc_deferred_product_sync = wp_parse_id_list( $wc_deferred_product_sync );
+ array_walk( $wc_deferred_product_sync, array( __CLASS__, 'deferred_product_sync' ) );
+ }
+ }
+
+ /**
+ * Sync a product.
+ *
+ * @param int $product_id Product ID.
+ */
+ public static function deferred_product_sync( $product_id ) {
+ $product = wc_get_product( $product_id );
+
+ if ( is_callable( array( $product, 'sync' ) ) ) {
+ $product->sync( $product );
+ }
+ }
+
+ /**
+ * When a post status changes.
+ *
+ * @param string $new_status New status.
+ * @param string $old_status Old status.
+ * @param WP_Post $post Post data.
+ */
+ public static function transition_post_status( $new_status, $old_status, $post ) {
+ if ( ( 'publish' === $new_status || 'publish' === $old_status ) && in_array( $post->post_type, array( 'product', 'product_variation' ), true ) ) {
+ self::delete_product_query_transients();
+ }
+ }
+
+ /**
+ * Delete product view transients when needed e.g. when post status changes, or visibility/stock status is modified.
+ */
+ public static function delete_product_query_transients() {
+ WC_Cache_Helper::get_transient_version( 'product_query', true );
+ }
+
+ /**
+ * Handle type changes.
+ *
+ * @since 3.0.0
+ * @param WC_Product $product Product data.
+ * @param string $from Origin type.
+ * @param string $to New type.
+ */
+ public static function product_type_changed( $product, $from, $to ) {
+ if ( 'variable' === $from && 'variable' !== $to ) {
+ // If the product is no longer variable, we should ensure all variations are removed.
+ $data_store = WC_Data_Store::load( 'product-variable' );
+ $data_store->delete_variations( $product->get_id(), true );
+ }
+ }
+
+ /**
+ * When editing a term, check for product attributes.
+ *
+ * @param int $term_id Term ID.
+ * @param int $tt_id Term taxonomy ID.
+ * @param string $taxonomy Taxonomy slug.
+ */
+ public static function edit_term( $term_id, $tt_id, $taxonomy ) {
+ if ( strpos( $taxonomy, 'pa_' ) === 0 ) {
+ self::$editing_term = get_term_by( 'id', $term_id, $taxonomy );
+ } else {
+ self::$editing_term = null;
+ }
+ }
+
+ /**
+ * When a term is edited, check for product attributes and update variations.
+ *
+ * @param int $term_id Term ID.
+ * @param int $tt_id Term taxonomy ID.
+ * @param string $taxonomy Taxonomy slug.
+ */
+ public static function edited_term( $term_id, $tt_id, $taxonomy ) {
+ if ( ! is_null( self::$editing_term ) && strpos( $taxonomy, 'pa_' ) === 0 ) {
+ $edited_term = get_term_by( 'id', $term_id, $taxonomy );
+
+ if ( $edited_term->slug !== self::$editing_term->slug ) {
+ global $wpdb;
+
+ $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->postmeta} SET meta_value = %s WHERE meta_key = %s AND meta_value = %s;", $edited_term->slug, 'attribute_' . sanitize_title( $taxonomy ), self::$editing_term->slug ) );
+
+ $wpdb->query(
+ $wpdb->prepare(
+ "UPDATE {$wpdb->postmeta} SET meta_value = REPLACE( meta_value, %s, %s ) WHERE meta_key = '_default_attributes'",
+ serialize( self::$editing_term->taxonomy ) . serialize( self::$editing_term->slug ),
+ serialize( $edited_term->taxonomy ) . serialize( $edited_term->slug )
+ )
+ );
+ }
+ } else {
+ self::$editing_term = null;
+ }
+ }
+
+ /**
+ * Ensure floats are correctly converted to strings based on PHP locale.
+ *
+ * @param null $check Whether to allow updating metadata for the given type.
+ * @param int $object_id Object ID.
+ * @param string $meta_key Meta key.
+ * @param mixed $meta_value Meta value. Must be serializable if non-scalar.
+ * @param mixed $prev_value If specified, only update existing metadata entries with the specified value. Otherwise, update all entries.
+ * @return null|bool
+ */
+ public static function update_order_item_metadata( $check, $object_id, $meta_key, $meta_value, $prev_value ) {
+ if ( ! empty( $meta_value ) && is_float( $meta_value ) ) {
+
+ // Convert float to string.
+ $meta_value = wc_float_to_string( $meta_value );
+
+ // Update meta value with new string.
+ update_metadata( 'order_item', $object_id, $meta_key, $meta_value, $prev_value );
+
+ return true;
+ }
+ return $check;
+ }
+
+ /**
+ * Ensure floats are correctly converted to strings based on PHP locale.
+ *
+ * @param null $check Whether to allow updating metadata for the given type.
+ * @param int $object_id Object ID.
+ * @param string $meta_key Meta key.
+ * @param mixed $meta_value Meta value. Must be serializable if non-scalar.
+ * @param mixed $prev_value If specified, only update existing metadata entries with the specified value. Otherwise, update all entries.
+ * @return null|bool
+ */
+ public static function update_post_metadata( $check, $object_id, $meta_key, $meta_value, $prev_value ) {
+ // Delete product cache if someone uses meta directly.
+ if ( in_array( get_post_type( $object_id ), array( 'product', 'product_variation' ), true ) ) {
+ wp_cache_delete( 'product-' . $object_id, 'products' );
+ }
+
+ if ( ! empty( $meta_value ) && is_float( $meta_value ) && ! registered_meta_key_exists( 'post', $meta_key ) && in_array( get_post_type( $object_id ), array_merge( wc_get_order_types(), array( 'shop_coupon', 'product', 'product_variation' ) ), true ) ) {
+
+ // Convert float to string.
+ $meta_value = wc_float_to_string( $meta_value );
+
+ // Update meta value with new string.
+ update_metadata( 'post', $object_id, $meta_key, $meta_value, $prev_value );
+
+ return true;
+ }
+ return $check;
+ }
+
+ /**
+ * Forces the order posts to have a title in a certain format (containing the date).
+ * Forces certain product data based on the product's type, e.g. grouped products cannot have a parent.
+ *
+ * @param array $data An array of slashed post data.
+ * @return array
+ */
+ public static function wp_insert_post_data( $data ) {
+ if ( 'shop_order' === $data['post_type'] && isset( $data['post_date'] ) ) {
+ $order_title = 'Order';
+ if ( $data['post_date'] ) {
+ $order_title .= ' – ' . date_i18n( 'F j, Y @ h:i A', strtotime( $data['post_date'] ) );
+ }
+ $data['post_title'] = $order_title;
+ } elseif ( 'product' === $data['post_type'] && isset( $_POST['product-type'] ) ) { // WPCS: input var ok, CSRF ok.
+ $product_type = wc_clean( wp_unslash( $_POST['product-type'] ) ); // WPCS: input var ok, CSRF ok.
+ switch ( $product_type ) {
+ case 'grouped':
+ case 'variable':
+ $data['post_parent'] = 0;
+ break;
+ }
+ } elseif ( 'product' === $data['post_type'] && 'auto-draft' === $data['post_status'] ) {
+ $data['post_title'] = 'AUTO-DRAFT';
+ } elseif ( 'shop_coupon' === $data['post_type'] ) {
+ // Coupons should never allow unfiltered HTML.
+ $data['post_title'] = wp_filter_kses( $data['post_title'] );
+ }
+
+ return $data;
+ }
+
+ /**
+ * Change embed data for certain post types.
+ *
+ * @since 3.2.0
+ * @param array $data The response data.
+ * @param WP_Post $post The post object.
+ * @return array
+ */
+ public static function filter_oembed_response_data( $data, $post ) {
+ if ( in_array( $post->post_type, array( 'shop_order', 'shop_coupon' ), true ) ) {
+ return array();
+ }
+ return $data;
+ }
+
+ /**
+ * Removes variations etc belonging to a deleted post, and clears transients.
+ *
+ * @param mixed $id ID of post being deleted.
+ */
+ public static function delete_post( $id ) {
+ if ( ! current_user_can( 'delete_posts' ) || ! $id ) {
+ return;
+ }
+
+ $post_type = get_post_type( $id );
+
+ switch ( $post_type ) {
+ case 'product':
+ $data_store = WC_Data_Store::load( 'product-variable' );
+ $data_store->delete_variations( $id, true );
+ $data_store->delete_from_lookup_table( $id, 'wc_product_meta_lookup' );
+ $parent_id = wp_get_post_parent_id( $id );
+
+ if ( $parent_id ) {
+ wc_delete_product_transients( $parent_id );
+ }
+ break;
+ case 'product_variation':
+ $data_store = WC_Data_Store::load( 'product' );
+ $data_store->delete_from_lookup_table( $id, 'wc_product_meta_lookup' );
+ wc_delete_product_transients( wp_get_post_parent_id( $id ) );
+ break;
+ case 'shop_order':
+ global $wpdb;
+
+ $refunds = $wpdb->get_results( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type = 'shop_order_refund' AND post_parent = %d", $id ) );
+
+ if ( ! is_null( $refunds ) ) {
+ foreach ( $refunds as $refund ) {
+ wp_delete_post( $refund->ID, true );
+ }
+ }
+ break;
+ }
+ }
+
+ /**
+ * Trash post.
+ *
+ * @param mixed $id Post ID.
+ */
+ public static function trash_post( $id ) {
+ if ( ! $id ) {
+ return;
+ }
+
+ $post_type = get_post_type( $id );
+
+ // If this is an order, trash any refunds too.
+ if ( in_array( $post_type, wc_get_order_types( 'order-count' ), true ) ) {
+ global $wpdb;
+
+ $refunds = $wpdb->get_results( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type = 'shop_order_refund' AND post_parent = %d", $id ) );
+
+ foreach ( $refunds as $refund ) {
+ $wpdb->update( $wpdb->posts, array( 'post_status' => 'trash' ), array( 'ID' => $refund->ID ) );
+ }
+
+ wc_delete_shop_order_transients( $id );
+
+ // If this is a product, trash children variations.
+ } elseif ( 'product' === $post_type ) {
+ $data_store = WC_Data_Store::load( 'product-variable' );
+ $data_store->delete_variations( $id, false );
+ }
+ }
+
+ /**
+ * Untrash post.
+ *
+ * @param mixed $id Post ID.
+ */
+ public static function untrash_post( $id ) {
+ if ( ! $id ) {
+ return;
+ }
+
+ $post_type = get_post_type( $id );
+
+ if ( in_array( $post_type, wc_get_order_types( 'order-count' ), true ) ) {
+ global $wpdb;
+
+ $refunds = $wpdb->get_results( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type = 'shop_order_refund' AND post_parent = %d", $id ) );
+
+ foreach ( $refunds as $refund ) {
+ $wpdb->update( $wpdb->posts, array( 'post_status' => 'wc-completed' ), array( 'ID' => $refund->ID ) );
+ }
+
+ wc_delete_shop_order_transients( $id );
+
+ } elseif ( 'product' === $post_type ) {
+ $data_store = WC_Data_Store::load( 'product-variable' );
+ $data_store->untrash_variations( $id );
+
+ wc_product_force_unique_sku( $id );
+ }
+ }
+
+ /**
+ * Before deleting an order, do some cleanup.
+ *
+ * @since 3.2.0
+ * @param int $order_id Order ID.
+ */
+ public static function before_delete_order( $order_id ) {
+ if ( in_array( get_post_type( $order_id ), wc_get_order_types(), true ) ) {
+ // Clean up user.
+ $order = wc_get_order( $order_id );
+
+ // Check for `get_customer_id`, since this may be e.g. a refund order (which doesn't implement it).
+ $customer_id = is_callable( array( $order, 'get_customer_id' ) ) ? $order->get_customer_id() : 0;
+
+ if ( $customer_id > 0 && 'shop_order' === $order->get_type() ) {
+ $customer = new WC_Customer( $customer_id );
+ $order_count = $customer->get_order_count();
+ $order_count --;
+
+ if ( 0 === $order_count ) {
+ $customer->set_is_paying_customer( false );
+ $customer->save();
+ }
+
+ // Delete order count meta.
+ delete_user_meta( $customer_id, '_order_count' );
+ }
+
+ // Clean up items.
+ self::delete_order_items( $order_id );
+ self::delete_order_downloadable_permissions( $order_id );
+ }
+ }
+
+ /**
+ * Remove item meta on permanent deletion.
+ *
+ * @param int $postid Post ID.
+ */
+ public static function delete_order_items( $postid ) {
+ global $wpdb;
+
+ if ( in_array( get_post_type( $postid ), wc_get_order_types(), true ) ) {
+ do_action( 'woocommerce_delete_order_items', $postid );
+
+ $wpdb->query(
+ "
+ DELETE {$wpdb->prefix}woocommerce_order_items, {$wpdb->prefix}woocommerce_order_itemmeta
+ FROM {$wpdb->prefix}woocommerce_order_items
+ JOIN {$wpdb->prefix}woocommerce_order_itemmeta ON {$wpdb->prefix}woocommerce_order_items.order_item_id = {$wpdb->prefix}woocommerce_order_itemmeta.order_item_id
+ WHERE {$wpdb->prefix}woocommerce_order_items.order_id = '{$postid}';
+ "
+ ); // WPCS: unprepared SQL ok.
+
+ do_action( 'woocommerce_deleted_order_items', $postid );
+ }
+ }
+
+ /**
+ * Remove downloadable permissions on permanent order deletion.
+ *
+ * @param int $postid Post ID.
+ */
+ public static function delete_order_downloadable_permissions( $postid ) {
+ if ( in_array( get_post_type( $postid ), wc_get_order_types(), true ) ) {
+ do_action( 'woocommerce_delete_order_downloadable_permissions', $postid );
+
+ $data_store = WC_Data_Store::load( 'customer-download' );
+ $data_store->delete_by_order_id( $postid );
+
+ do_action( 'woocommerce_deleted_order_downloadable_permissions', $postid );
+ }
+ }
+
+ /**
+ * Flush meta cache for CRUD objects on direct update.
+ *
+ * @param int $meta_id Meta ID.
+ * @param int $object_id Object ID.
+ * @param string $meta_key Meta key.
+ * @param string $meta_value Meta value.
+ */
+ public static function flush_object_meta_cache( $meta_id, $object_id, $meta_key, $meta_value ) {
+ WC_Cache_Helper::invalidate_cache_group( 'object_' . $object_id );
+ }
+
+ /**
+ * Ensure default category gets set.
+ *
+ * @since 3.3.0
+ * @param int $object_id Product ID.
+ * @param array $terms Terms array.
+ * @param array $tt_ids Term ids array.
+ * @param string $taxonomy Taxonomy name.
+ * @param bool $append Are we appending or setting terms.
+ */
+ public static function force_default_term( $object_id, $terms, $tt_ids, $taxonomy, $append ) {
+ if ( ! $append && 'product_cat' === $taxonomy && empty( $tt_ids ) && 'product' === get_post_type( $object_id ) ) {
+ $default_term = absint( get_option( 'default_product_cat', 0 ) );
+ $tt_ids = array_map( 'absint', $tt_ids );
+
+ if ( $default_term && ! in_array( $default_term, $tt_ids, true ) ) {
+ wp_set_post_terms( $object_id, array( $default_term ), 'product_cat', true );
+ }
+ }
+ }
+
+ /**
+ * When setting stock level, ensure the stock status is kept in sync.
+ *
+ * @param int $meta_id Meta ID.
+ * @param int $object_id Object ID.
+ * @param string $meta_key Meta key.
+ * @param mixed $meta_value Meta value.
+ * @deprecated 3.3
+ */
+ public static function sync_product_stock_status( $meta_id, $object_id, $meta_key, $meta_value ) {}
+
+ /**
+ * Update changed downloads.
+ *
+ * @deprecated 3.3.0 No action is necessary on changes to download paths since download_id is no longer based on file hash.
+ * @param int $product_id Product ID.
+ * @param int $variation_id Variation ID. Optional product variation identifier.
+ * @param array $downloads Newly set files.
+ */
+ public static function process_product_file_download_paths( $product_id, $variation_id, $downloads ) {
+ wc_deprecated_function( __FUNCTION__, '3.3' );
+ }
+
+ /**
+ * Delete transients when terms are set.
+ *
+ * @deprecated 3.6
+ * @param int $object_id Object ID.
+ * @param mixed $terms An array of object terms.
+ * @param array $tt_ids An array of term taxonomy IDs.
+ * @param string $taxonomy Taxonomy slug.
+ * @param mixed $append Whether to append new terms to the old terms.
+ * @param array $old_tt_ids Old array of term taxonomy IDs.
+ */
+ public static function set_object_terms( $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids ) {
+ if ( in_array( get_post_type( $object_id ), array( 'product', 'product_variation' ), true ) ) {
+ self::delete_product_query_transients();
+ }
+ }
+}
+
+WC_Post_Data::init();
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-post-types.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-post-types.php
new file mode 100644
index 0000000..2a2255b
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-post-types.php
@@ -0,0 +1,676 @@
+ false,
+ 'show_ui' => false,
+ 'show_in_nav_menus' => false,
+ 'query_var' => is_admin(),
+ 'rewrite' => false,
+ 'public' => false,
+ 'label' => _x( 'Product type', 'Taxonomy name', 'woocommerce' ),
+ )
+ )
+ );
+
+ register_taxonomy(
+ 'product_visibility',
+ apply_filters( 'woocommerce_taxonomy_objects_product_visibility', array( 'product', 'product_variation' ) ),
+ apply_filters(
+ 'woocommerce_taxonomy_args_product_visibility',
+ array(
+ 'hierarchical' => false,
+ 'show_ui' => false,
+ 'show_in_nav_menus' => false,
+ 'query_var' => is_admin(),
+ 'rewrite' => false,
+ 'public' => false,
+ 'label' => _x( 'Product visibility', 'Taxonomy name', 'woocommerce' ),
+ )
+ )
+ );
+
+ register_taxonomy(
+ 'product_cat',
+ apply_filters( 'woocommerce_taxonomy_objects_product_cat', array( 'product' ) ),
+ apply_filters(
+ 'woocommerce_taxonomy_args_product_cat',
+ array(
+ 'hierarchical' => true,
+ 'update_count_callback' => '_wc_term_recount',
+ 'label' => __( 'Categories', 'woocommerce' ),
+ 'labels' => array(
+ 'name' => __( 'Product categories', 'woocommerce' ),
+ 'singular_name' => __( 'Category', 'woocommerce' ),
+ 'menu_name' => _x( 'Categories', 'Admin menu name', 'woocommerce' ),
+ 'search_items' => __( 'Search categories', 'woocommerce' ),
+ 'all_items' => __( 'All categories', 'woocommerce' ),
+ 'parent_item' => __( 'Parent category', 'woocommerce' ),
+ 'parent_item_colon' => __( 'Parent category:', 'woocommerce' ),
+ 'edit_item' => __( 'Edit category', 'woocommerce' ),
+ 'update_item' => __( 'Update category', 'woocommerce' ),
+ 'add_new_item' => __( 'Add new category', 'woocommerce' ),
+ 'new_item_name' => __( 'New category name', 'woocommerce' ),
+ 'not_found' => __( 'No categories found', 'woocommerce' ),
+ ),
+ 'show_ui' => true,
+ 'query_var' => true,
+ 'capabilities' => array(
+ 'manage_terms' => 'manage_product_terms',
+ 'edit_terms' => 'edit_product_terms',
+ 'delete_terms' => 'delete_product_terms',
+ 'assign_terms' => 'assign_product_terms',
+ ),
+ 'rewrite' => array(
+ 'slug' => $permalinks['category_rewrite_slug'],
+ 'with_front' => false,
+ 'hierarchical' => true,
+ ),
+ )
+ )
+ );
+
+ register_taxonomy(
+ 'product_tag',
+ apply_filters( 'woocommerce_taxonomy_objects_product_tag', array( 'product' ) ),
+ apply_filters(
+ 'woocommerce_taxonomy_args_product_tag',
+ array(
+ 'hierarchical' => false,
+ 'update_count_callback' => '_wc_term_recount',
+ 'label' => __( 'Product tags', 'woocommerce' ),
+ 'labels' => array(
+ 'name' => __( 'Product tags', 'woocommerce' ),
+ 'singular_name' => __( 'Tag', 'woocommerce' ),
+ 'menu_name' => _x( 'Tags', 'Admin menu name', 'woocommerce' ),
+ 'search_items' => __( 'Search tags', 'woocommerce' ),
+ 'all_items' => __( 'All tags', 'woocommerce' ),
+ 'edit_item' => __( 'Edit tag', 'woocommerce' ),
+ 'update_item' => __( 'Update tag', 'woocommerce' ),
+ 'add_new_item' => __( 'Add new tag', 'woocommerce' ),
+ 'new_item_name' => __( 'New tag name', 'woocommerce' ),
+ 'popular_items' => __( 'Popular tags', 'woocommerce' ),
+ 'separate_items_with_commas' => __( 'Separate tags with commas', 'woocommerce' ),
+ 'add_or_remove_items' => __( 'Add or remove tags', 'woocommerce' ),
+ 'choose_from_most_used' => __( 'Choose from the most used tags', 'woocommerce' ),
+ 'not_found' => __( 'No tags found', 'woocommerce' ),
+ ),
+ 'show_ui' => true,
+ 'query_var' => true,
+ 'capabilities' => array(
+ 'manage_terms' => 'manage_product_terms',
+ 'edit_terms' => 'edit_product_terms',
+ 'delete_terms' => 'delete_product_terms',
+ 'assign_terms' => 'assign_product_terms',
+ ),
+ 'rewrite' => array(
+ 'slug' => $permalinks['tag_rewrite_slug'],
+ 'with_front' => false,
+ ),
+ )
+ )
+ );
+
+ register_taxonomy(
+ 'product_shipping_class',
+ apply_filters( 'woocommerce_taxonomy_objects_product_shipping_class', array( 'product', 'product_variation' ) ),
+ apply_filters(
+ 'woocommerce_taxonomy_args_product_shipping_class',
+ array(
+ 'hierarchical' => false,
+ 'update_count_callback' => '_update_post_term_count',
+ 'label' => __( 'Shipping classes', 'woocommerce' ),
+ 'labels' => array(
+ 'name' => __( 'Product shipping classes', 'woocommerce' ),
+ 'singular_name' => __( 'Shipping class', 'woocommerce' ),
+ 'menu_name' => _x( 'Shipping classes', 'Admin menu name', 'woocommerce' ),
+ 'search_items' => __( 'Search shipping classes', 'woocommerce' ),
+ 'all_items' => __( 'All shipping classes', 'woocommerce' ),
+ 'parent_item' => __( 'Parent shipping class', 'woocommerce' ),
+ 'parent_item_colon' => __( 'Parent shipping class:', 'woocommerce' ),
+ 'edit_item' => __( 'Edit shipping class', 'woocommerce' ),
+ 'update_item' => __( 'Update shipping class', 'woocommerce' ),
+ 'add_new_item' => __( 'Add new shipping class', 'woocommerce' ),
+ 'new_item_name' => __( 'New shipping class Name', 'woocommerce' ),
+ ),
+ 'show_ui' => false,
+ 'show_in_quick_edit' => false,
+ 'show_in_nav_menus' => false,
+ 'query_var' => is_admin(),
+ 'capabilities' => array(
+ 'manage_terms' => 'manage_product_terms',
+ 'edit_terms' => 'edit_product_terms',
+ 'delete_terms' => 'delete_product_terms',
+ 'assign_terms' => 'assign_product_terms',
+ ),
+ 'rewrite' => false,
+ )
+ )
+ );
+
+ global $wc_product_attributes;
+
+ $wc_product_attributes = array();
+ $attribute_taxonomies = wc_get_attribute_taxonomies();
+
+ if ( $attribute_taxonomies ) {
+ foreach ( $attribute_taxonomies as $tax ) {
+ $name = wc_attribute_taxonomy_name( $tax->attribute_name );
+
+ if ( $name ) {
+ $tax->attribute_public = absint( isset( $tax->attribute_public ) ? $tax->attribute_public : 1 );
+ $label = ! empty( $tax->attribute_label ) ? $tax->attribute_label : $tax->attribute_name;
+ $wc_product_attributes[ $name ] = $tax;
+ $taxonomy_data = array(
+ 'hierarchical' => false,
+ 'update_count_callback' => '_update_post_term_count',
+ 'labels' => array(
+ /* translators: %s: attribute name */
+ 'name' => sprintf( _x( 'Product %s', 'Product Attribute', 'woocommerce' ), $label ),
+ 'singular_name' => $label,
+ /* translators: %s: attribute name */
+ 'search_items' => sprintf( __( 'Search %s', 'woocommerce' ), $label ),
+ /* translators: %s: attribute name */
+ 'all_items' => sprintf( __( 'All %s', 'woocommerce' ), $label ),
+ /* translators: %s: attribute name */
+ 'parent_item' => sprintf( __( 'Parent %s', 'woocommerce' ), $label ),
+ /* translators: %s: attribute name */
+ 'parent_item_colon' => sprintf( __( 'Parent %s:', 'woocommerce' ), $label ),
+ /* translators: %s: attribute name */
+ 'edit_item' => sprintf( __( 'Edit %s', 'woocommerce' ), $label ),
+ /* translators: %s: attribute name */
+ 'update_item' => sprintf( __( 'Update %s', 'woocommerce' ), $label ),
+ /* translators: %s: attribute name */
+ 'add_new_item' => sprintf( __( 'Add new %s', 'woocommerce' ), $label ),
+ /* translators: %s: attribute name */
+ 'new_item_name' => sprintf( __( 'New %s', 'woocommerce' ), $label ),
+ /* translators: %s: attribute name */
+ 'not_found' => sprintf( __( 'No "%s" found', 'woocommerce' ), $label ),
+ /* translators: %s: attribute name */
+ 'back_to_items' => sprintf( __( '← Back to "%s" attributes', 'woocommerce' ), $label ),
+ ),
+ 'show_ui' => true,
+ 'show_in_quick_edit' => false,
+ 'show_in_menu' => false,
+ 'meta_box_cb' => false,
+ 'query_var' => 1 === $tax->attribute_public,
+ 'rewrite' => false,
+ 'sort' => false,
+ 'public' => 1 === $tax->attribute_public,
+ 'show_in_nav_menus' => 1 === $tax->attribute_public && apply_filters( 'woocommerce_attribute_show_in_nav_menus', false, $name ),
+ 'capabilities' => array(
+ 'manage_terms' => 'manage_product_terms',
+ 'edit_terms' => 'edit_product_terms',
+ 'delete_terms' => 'delete_product_terms',
+ 'assign_terms' => 'assign_product_terms',
+ ),
+ );
+
+ if ( 1 === $tax->attribute_public && sanitize_title( $tax->attribute_name ) ) {
+ $taxonomy_data['rewrite'] = array(
+ 'slug' => trailingslashit( $permalinks['attribute_rewrite_slug'] ) . sanitize_title( $tax->attribute_name ),
+ 'with_front' => false,
+ 'hierarchical' => true,
+ );
+ }
+
+ register_taxonomy( $name, apply_filters( "woocommerce_taxonomy_objects_{$name}", array( 'product' ) ), apply_filters( "woocommerce_taxonomy_args_{$name}", $taxonomy_data ) );
+ }
+ }
+ }
+
+ do_action( 'woocommerce_after_register_taxonomy' );
+ }
+
+ /**
+ * Register core post types.
+ */
+ public static function register_post_types() {
+ if ( ! is_blog_installed() || post_type_exists( 'product' ) ) {
+ return;
+ }
+
+ do_action( 'woocommerce_register_post_type' );
+
+ $permalinks = wc_get_permalink_structure();
+ $supports = array( 'title', 'editor', 'excerpt', 'thumbnail', 'custom-fields', 'publicize', 'wpcom-markdown' );
+
+ if ( 'yes' === get_option( 'woocommerce_enable_reviews', 'yes' ) ) {
+ $supports[] = 'comments';
+ }
+
+ $shop_page_id = wc_get_page_id( 'shop' );
+
+ if ( current_theme_supports( 'woocommerce' ) ) {
+ $has_archive = $shop_page_id && get_post( $shop_page_id ) ? urldecode( get_page_uri( $shop_page_id ) ) : 'shop';
+ } else {
+ $has_archive = false;
+ }
+
+ // If theme support changes, we may need to flush permalinks since some are changed based on this flag.
+ $theme_support = current_theme_supports( 'woocommerce' ) ? 'yes' : 'no';
+ if ( get_option( 'current_theme_supports_woocommerce' ) !== $theme_support && update_option( 'current_theme_supports_woocommerce', $theme_support ) ) {
+ update_option( 'woocommerce_queue_flush_rewrite_rules', 'yes' );
+ }
+
+ register_post_type(
+ 'product',
+ apply_filters(
+ 'woocommerce_register_post_type_product',
+ array(
+ 'labels' => array(
+ 'name' => __( 'Products', 'woocommerce' ),
+ 'singular_name' => __( 'Product', 'woocommerce' ),
+ 'all_items' => __( 'All Products', 'woocommerce' ),
+ 'menu_name' => _x( 'Products', 'Admin menu name', 'woocommerce' ),
+ 'add_new' => __( 'Add New', 'woocommerce' ),
+ 'add_new_item' => __( 'Add new product', 'woocommerce' ),
+ 'edit' => __( 'Edit', 'woocommerce' ),
+ 'edit_item' => __( 'Edit product', 'woocommerce' ),
+ 'new_item' => __( 'New product', 'woocommerce' ),
+ 'view_item' => __( 'View product', 'woocommerce' ),
+ 'view_items' => __( 'View products', 'woocommerce' ),
+ 'search_items' => __( 'Search products', 'woocommerce' ),
+ 'not_found' => __( 'No products found', 'woocommerce' ),
+ 'not_found_in_trash' => __( 'No products found in trash', 'woocommerce' ),
+ 'parent' => __( 'Parent product', 'woocommerce' ),
+ 'featured_image' => __( 'Product image', 'woocommerce' ),
+ 'set_featured_image' => __( 'Set product image', 'woocommerce' ),
+ 'remove_featured_image' => __( 'Remove product image', 'woocommerce' ),
+ 'use_featured_image' => __( 'Use as product image', 'woocommerce' ),
+ 'insert_into_item' => __( 'Insert into product', 'woocommerce' ),
+ 'uploaded_to_this_item' => __( 'Uploaded to this product', 'woocommerce' ),
+ 'filter_items_list' => __( 'Filter products', 'woocommerce' ),
+ 'items_list_navigation' => __( 'Products navigation', 'woocommerce' ),
+ 'items_list' => __( 'Products list', 'woocommerce' ),
+ ),
+ 'description' => __( 'This is where you can add new products to your store.', 'woocommerce' ),
+ 'public' => true,
+ 'show_ui' => true,
+ 'capability_type' => 'product',
+ 'map_meta_cap' => true,
+ 'publicly_queryable' => true,
+ 'exclude_from_search' => false,
+ 'hierarchical' => false, // Hierarchical causes memory issues - WP loads all records!
+ 'rewrite' => $permalinks['product_rewrite_slug'] ? array(
+ 'slug' => $permalinks['product_rewrite_slug'],
+ 'with_front' => false,
+ 'feeds' => true,
+ ) : false,
+ 'query_var' => true,
+ 'supports' => $supports,
+ 'has_archive' => $has_archive,
+ 'show_in_nav_menus' => true,
+ 'show_in_rest' => true,
+ )
+ )
+ );
+
+ register_post_type(
+ 'product_variation',
+ apply_filters(
+ 'woocommerce_register_post_type_product_variation',
+ array(
+ 'label' => __( 'Variations', 'woocommerce' ),
+ 'public' => false,
+ 'hierarchical' => false,
+ 'supports' => false,
+ 'capability_type' => 'product',
+ 'rewrite' => false,
+ )
+ )
+ );
+
+ wc_register_order_type(
+ 'shop_order',
+ apply_filters(
+ 'woocommerce_register_post_type_shop_order',
+ array(
+ 'labels' => array(
+ 'name' => __( 'Orders', 'woocommerce' ),
+ 'singular_name' => _x( 'Order', 'shop_order post type singular name', 'woocommerce' ),
+ 'add_new' => __( 'Add order', 'woocommerce' ),
+ 'add_new_item' => __( 'Add new order', 'woocommerce' ),
+ 'edit' => __( 'Edit', 'woocommerce' ),
+ 'edit_item' => __( 'Edit order', 'woocommerce' ),
+ 'new_item' => __( 'New order', 'woocommerce' ),
+ 'view_item' => __( 'View order', 'woocommerce' ),
+ 'search_items' => __( 'Search orders', 'woocommerce' ),
+ 'not_found' => __( 'No orders found', 'woocommerce' ),
+ 'not_found_in_trash' => __( 'No orders found in trash', 'woocommerce' ),
+ 'parent' => __( 'Parent orders', 'woocommerce' ),
+ 'menu_name' => _x( 'Orders', 'Admin menu name', 'woocommerce' ),
+ 'filter_items_list' => __( 'Filter orders', 'woocommerce' ),
+ 'items_list_navigation' => __( 'Orders navigation', 'woocommerce' ),
+ 'items_list' => __( 'Orders list', 'woocommerce' ),
+ ),
+ 'description' => __( 'This is where store orders are stored.', 'woocommerce' ),
+ 'public' => false,
+ 'show_ui' => true,
+ 'capability_type' => 'shop_order',
+ 'map_meta_cap' => true,
+ 'publicly_queryable' => false,
+ 'exclude_from_search' => true,
+ 'show_in_menu' => current_user_can( 'edit_others_shop_orders' ) ? 'woocommerce' : true,
+ 'hierarchical' => false,
+ 'show_in_nav_menus' => false,
+ 'rewrite' => false,
+ 'query_var' => false,
+ 'supports' => array( 'title', 'comments', 'custom-fields' ),
+ 'has_archive' => false,
+ )
+ )
+ );
+
+ wc_register_order_type(
+ 'shop_order_refund',
+ apply_filters(
+ 'woocommerce_register_post_type_shop_order_refund',
+ array(
+ 'label' => __( 'Refunds', 'woocommerce' ),
+ 'capability_type' => 'shop_order',
+ 'public' => false,
+ 'hierarchical' => false,
+ 'supports' => false,
+ 'exclude_from_orders_screen' => false,
+ 'add_order_meta_boxes' => false,
+ 'exclude_from_order_count' => true,
+ 'exclude_from_order_views' => false,
+ 'exclude_from_order_reports' => false,
+ 'exclude_from_order_sales_reports' => true,
+ 'class_name' => 'WC_Order_Refund',
+ 'rewrite' => false,
+ )
+ )
+ );
+
+ if ( 'yes' === get_option( 'woocommerce_enable_coupons' ) ) {
+ register_post_type(
+ 'shop_coupon',
+ apply_filters(
+ 'woocommerce_register_post_type_shop_coupon',
+ array(
+ 'labels' => array(
+ 'name' => __( 'Coupons', 'woocommerce' ),
+ 'singular_name' => __( 'Coupon', 'woocommerce' ),
+ 'menu_name' => _x( 'Coupons', 'Admin menu name', 'woocommerce' ),
+ 'add_new' => __( 'Add coupon', 'woocommerce' ),
+ 'add_new_item' => __( 'Add new coupon', 'woocommerce' ),
+ 'edit' => __( 'Edit', 'woocommerce' ),
+ 'edit_item' => __( 'Edit coupon', 'woocommerce' ),
+ 'new_item' => __( 'New coupon', 'woocommerce' ),
+ 'view_item' => __( 'View coupon', 'woocommerce' ),
+ 'search_items' => __( 'Search coupons', 'woocommerce' ),
+ 'not_found' => __( 'No coupons found', 'woocommerce' ),
+ 'not_found_in_trash' => __( 'No coupons found in trash', 'woocommerce' ),
+ 'parent' => __( 'Parent coupon', 'woocommerce' ),
+ 'filter_items_list' => __( 'Filter coupons', 'woocommerce' ),
+ 'items_list_navigation' => __( 'Coupons navigation', 'woocommerce' ),
+ 'items_list' => __( 'Coupons list', 'woocommerce' ),
+ ),
+ 'description' => __( 'This is where you can add new coupons that customers can use in your store.', 'woocommerce' ),
+ 'public' => false,
+ 'show_ui' => true,
+ 'capability_type' => 'shop_coupon',
+ 'map_meta_cap' => true,
+ 'publicly_queryable' => false,
+ 'exclude_from_search' => true,
+ 'show_in_menu' => current_user_can( 'edit_others_shop_orders' ) ? 'woocommerce' : true,
+ 'hierarchical' => false,
+ 'rewrite' => false,
+ 'query_var' => false,
+ 'supports' => array( 'title' ),
+ 'show_in_nav_menus' => false,
+ 'show_in_admin_bar' => true,
+ )
+ )
+ );
+ }
+
+ do_action( 'woocommerce_after_register_post_type' );
+ }
+
+ /**
+ * Customize taxonomies update messages.
+ *
+ * @param array $messages The list of available messages.
+ * @since 4.4.0
+ * @return bool
+ */
+ public static function updated_term_messages( $messages ) {
+ $messages['product_cat'] = array(
+ 0 => '',
+ 1 => __( 'Category added.', 'woocommerce' ),
+ 2 => __( 'Category deleted.', 'woocommerce' ),
+ 3 => __( 'Category updated.', 'woocommerce' ),
+ 4 => __( 'Category not added.', 'woocommerce' ),
+ 5 => __( 'Category not updated.', 'woocommerce' ),
+ 6 => __( 'Categories deleted.', 'woocommerce' ),
+ );
+
+ $messages['product_tag'] = array(
+ 0 => '',
+ 1 => __( 'Tag added.', 'woocommerce' ),
+ 2 => __( 'Tag deleted.', 'woocommerce' ),
+ 3 => __( 'Tag updated.', 'woocommerce' ),
+ 4 => __( 'Tag not added.', 'woocommerce' ),
+ 5 => __( 'Tag not updated.', 'woocommerce' ),
+ 6 => __( 'Tags deleted.', 'woocommerce' ),
+ );
+
+ $wc_product_attributes = array();
+ $attribute_taxonomies = wc_get_attribute_taxonomies();
+
+ if ( $attribute_taxonomies ) {
+ foreach ( $attribute_taxonomies as $tax ) {
+ $name = wc_attribute_taxonomy_name( $tax->attribute_name );
+
+ if ( $name ) {
+ $label = ! empty( $tax->attribute_label ) ? $tax->attribute_label : $tax->attribute_name;
+
+ $messages[ $name ] = array(
+ 0 => '',
+ /* translators: %s: taxonomy label */
+ 1 => sprintf( _x( '%s added', 'taxonomy term messages', 'woocommerce' ), $label ),
+ /* translators: %s: taxonomy label */
+ 2 => sprintf( _x( '%s deleted', 'taxonomy term messages', 'woocommerce' ), $label ),
+ /* translators: %s: taxonomy label */
+ 3 => sprintf( _x( '%s updated', 'taxonomy term messages', 'woocommerce' ), $label ),
+ /* translators: %s: taxonomy label */
+ 4 => sprintf( _x( '%s not added', 'taxonomy term messages', 'woocommerce' ), $label ),
+ /* translators: %s: taxonomy label */
+ 5 => sprintf( _x( '%s not updated', 'taxonomy term messages', 'woocommerce' ), $label ),
+ /* translators: %s: taxonomy label */
+ 6 => sprintf( _x( '%s deleted', 'taxonomy term messages', 'woocommerce' ), $label ),
+ );
+ }
+ }
+ }
+
+ return $messages;
+ }
+
+ /**
+ * Register our custom post statuses, used for order status.
+ */
+ public static function register_post_status() {
+
+ $order_statuses = apply_filters(
+ 'woocommerce_register_shop_order_post_statuses',
+ array(
+ 'wc-pending' => array(
+ 'label' => _x( 'Pending payment', 'Order status', 'woocommerce' ),
+ 'public' => false,
+ 'exclude_from_search' => false,
+ 'show_in_admin_all_list' => true,
+ 'show_in_admin_status_list' => true,
+ /* translators: %s: number of orders */
+ 'label_count' => _n_noop( 'Pending payment (%s)', 'Pending payment (%s)', 'woocommerce' ),
+ ),
+ 'wc-processing' => array(
+ 'label' => _x( 'Processing', 'Order status', 'woocommerce' ),
+ 'public' => false,
+ 'exclude_from_search' => false,
+ 'show_in_admin_all_list' => true,
+ 'show_in_admin_status_list' => true,
+ /* translators: %s: number of orders */
+ 'label_count' => _n_noop( 'Processing (%s)', 'Processing (%s)', 'woocommerce' ),
+ ),
+ 'wc-on-hold' => array(
+ 'label' => _x( 'On hold', 'Order status', 'woocommerce' ),
+ 'public' => false,
+ 'exclude_from_search' => false,
+ 'show_in_admin_all_list' => true,
+ 'show_in_admin_status_list' => true,
+ /* translators: %s: number of orders */
+ 'label_count' => _n_noop( 'On hold (%s)', 'On hold (%s)', 'woocommerce' ),
+ ),
+ 'wc-completed' => array(
+ 'label' => _x( 'Completed', 'Order status', 'woocommerce' ),
+ 'public' => false,
+ 'exclude_from_search' => false,
+ 'show_in_admin_all_list' => true,
+ 'show_in_admin_status_list' => true,
+ /* translators: %s: number of orders */
+ 'label_count' => _n_noop( 'Completed (%s)', 'Completed (%s)', 'woocommerce' ),
+ ),
+ 'wc-cancelled' => array(
+ 'label' => _x( 'Cancelled', 'Order status', 'woocommerce' ),
+ 'public' => false,
+ 'exclude_from_search' => false,
+ 'show_in_admin_all_list' => true,
+ 'show_in_admin_status_list' => true,
+ /* translators: %s: number of orders */
+ 'label_count' => _n_noop( 'Cancelled (%s)', 'Cancelled (%s)', 'woocommerce' ),
+ ),
+ 'wc-refunded' => array(
+ 'label' => _x( 'Refunded', 'Order status', 'woocommerce' ),
+ 'public' => false,
+ 'exclude_from_search' => false,
+ 'show_in_admin_all_list' => true,
+ 'show_in_admin_status_list' => true,
+ /* translators: %s: number of orders */
+ 'label_count' => _n_noop( 'Refunded (%s)', 'Refunded (%s)', 'woocommerce' ),
+ ),
+ 'wc-failed' => array(
+ 'label' => _x( 'Failed', 'Order status', 'woocommerce' ),
+ 'public' => false,
+ 'exclude_from_search' => false,
+ 'show_in_admin_all_list' => true,
+ 'show_in_admin_status_list' => true,
+ /* translators: %s: number of orders */
+ 'label_count' => _n_noop( 'Failed (%s)', 'Failed (%s)', 'woocommerce' ),
+ ),
+ )
+ );
+
+ foreach ( $order_statuses as $order_status => $values ) {
+ register_post_status( $order_status, $values );
+ }
+ }
+
+ /**
+ * Flush rules if the event is queued.
+ *
+ * @since 3.3.0
+ */
+ public static function maybe_flush_rewrite_rules() {
+ if ( 'yes' === get_option( 'woocommerce_queue_flush_rewrite_rules' ) ) {
+ update_option( 'woocommerce_queue_flush_rewrite_rules', 'no' );
+ self::flush_rewrite_rules();
+ }
+ }
+
+ /**
+ * Flush rewrite rules.
+ */
+ public static function flush_rewrite_rules() {
+ flush_rewrite_rules();
+ }
+
+ /**
+ * Disable Gutenberg for products.
+ *
+ * @param bool $can_edit Whether the post type can be edited or not.
+ * @param string $post_type The post type being checked.
+ * @return bool
+ */
+ public static function gutenberg_can_edit_post_type( $can_edit, $post_type ) {
+ return 'product' === $post_type ? false : $can_edit;
+ }
+
+ /**
+ * Add Product Support to Jetpack Omnisearch.
+ */
+ public static function support_jetpack_omnisearch() {
+ if ( class_exists( 'Jetpack_Omnisearch_Posts' ) ) {
+ new Jetpack_Omnisearch_Posts( 'product' );
+ }
+ }
+
+ /**
+ * Added product for Jetpack related posts.
+ *
+ * @param array $post_types Post types.
+ * @return array
+ */
+ public static function rest_api_allowed_post_types( $post_types ) {
+ $post_types[] = 'product';
+
+ return $post_types;
+ }
+}
+
+WC_Post_types::init();
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-privacy-background-process.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-privacy-background-process.php
new file mode 100644
index 0000000..f75fa42
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-privacy-background-process.php
@@ -0,0 +1,70 @@
+prefix = 'wp_' . get_current_blog_id();
+ $this->action = 'wc_privacy_cleanup';
+ parent::__construct();
+ }
+
+ /**
+ * Code to execute for each item in the queue
+ *
+ * @param string $item Queue item to iterate over.
+ * @return bool
+ */
+ protected function task( $item ) {
+ if ( ! $item || empty( $item['task'] ) ) {
+ return false;
+ }
+
+ $process_count = 0;
+ $process_limit = 20;
+
+ switch ( $item['task'] ) {
+ case 'trash_pending_orders':
+ $process_count = WC_Privacy::trash_pending_orders( $process_limit );
+ break;
+ case 'trash_failed_orders':
+ $process_count = WC_Privacy::trash_failed_orders( $process_limit );
+ break;
+ case 'trash_cancelled_orders':
+ $process_count = WC_Privacy::trash_cancelled_orders( $process_limit );
+ break;
+ case 'anonymize_completed_orders':
+ $process_count = WC_Privacy::anonymize_completed_orders( $process_limit );
+ break;
+ case 'delete_inactive_accounts':
+ $process_count = WC_Privacy::delete_inactive_accounts( $process_limit );
+ break;
+ }
+
+ if ( $process_limit === $process_count ) {
+ // Needs to run again.
+ return $item;
+ }
+
+ return false;
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-privacy-erasers.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-privacy-erasers.php
new file mode 100644
index 0000000..463e236
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-privacy-erasers.php
@@ -0,0 +1,412 @@
+ false,
+ 'items_retained' => false,
+ 'messages' => array(),
+ 'done' => true,
+ );
+
+ $user = get_user_by( 'email', $email_address ); // Check if user has an ID in the DB to load stored personal data.
+
+ if ( ! $user instanceof WP_User ) {
+ return $response;
+ }
+
+ $customer = new WC_Customer( $user->ID );
+
+ if ( ! $customer ) {
+ return $response;
+ }
+
+ $props_to_erase = apply_filters(
+ 'woocommerce_privacy_erase_customer_personal_data_props',
+ array(
+ 'billing_first_name' => __( 'Billing First Name', 'woocommerce' ),
+ 'billing_last_name' => __( 'Billing Last Name', 'woocommerce' ),
+ 'billing_company' => __( 'Billing Company', 'woocommerce' ),
+ 'billing_address_1' => __( 'Billing Address 1', 'woocommerce' ),
+ 'billing_address_2' => __( 'Billing Address 2', 'woocommerce' ),
+ 'billing_city' => __( 'Billing City', 'woocommerce' ),
+ 'billing_postcode' => __( 'Billing Postal/Zip Code', 'woocommerce' ),
+ 'billing_state' => __( 'Billing State', 'woocommerce' ),
+ 'billing_country' => __( 'Billing Country / Region', 'woocommerce' ),
+ 'billing_phone' => __( 'Phone Number', 'woocommerce' ),
+ 'billing_email' => __( 'Email Address', 'woocommerce' ),
+ 'shipping_first_name' => __( 'Shipping First Name', 'woocommerce' ),
+ 'shipping_last_name' => __( 'Shipping Last Name', 'woocommerce' ),
+ 'shipping_company' => __( 'Shipping Company', 'woocommerce' ),
+ 'shipping_address_1' => __( 'Shipping Address 1', 'woocommerce' ),
+ 'shipping_address_2' => __( 'Shipping Address 2', 'woocommerce' ),
+ 'shipping_city' => __( 'Shipping City', 'woocommerce' ),
+ 'shipping_postcode' => __( 'Shipping Postal/Zip Code', 'woocommerce' ),
+ 'shipping_state' => __( 'Shipping State', 'woocommerce' ),
+ 'shipping_country' => __( 'Shipping Country / Region', 'woocommerce' ),
+ ),
+ $customer
+ );
+
+ foreach ( $props_to_erase as $prop => $label ) {
+ $erased = false;
+
+ if ( is_callable( array( $customer, 'get_' . $prop ) ) && is_callable( array( $customer, 'set_' . $prop ) ) ) {
+ $value = $customer->{"get_$prop"}( 'edit' );
+
+ if ( $value ) {
+ $customer->{"set_$prop"}( '' );
+ $erased = true;
+ }
+ }
+
+ $erased = apply_filters( 'woocommerce_privacy_erase_customer_personal_data_prop', $erased, $prop, $customer );
+
+ if ( $erased ) {
+ /* Translators: %s Prop name. */
+ $response['messages'][] = sprintf( __( 'Removed customer "%s"', 'woocommerce' ), $label );
+ $response['items_removed'] = true;
+ }
+ }
+
+ $customer->save();
+
+ /**
+ * Allow extensions to remove data for this customer and adjust the response.
+ *
+ * @since 3.4.0
+ * @param array $response Array resonse data. Must include messages, num_items_removed, num_items_retained, done.
+ * @param WC_Order $order A customer object.
+ */
+ return apply_filters( 'woocommerce_privacy_erase_personal_data_customer', $response, $customer );
+ }
+
+ /**
+ * Finds and erases data which could be used to identify a person from WooCommerce data assocated with an email address.
+ *
+ * Orders are erased in blocks of 10 to avoid timeouts.
+ *
+ * @since 3.4.0
+ * @param string $email_address The user email address.
+ * @param int $page Page.
+ * @return array An array of personal data in name value pairs
+ */
+ public static function order_data_eraser( $email_address, $page ) {
+ $page = (int) $page;
+ $user = get_user_by( 'email', $email_address ); // Check if user has an ID in the DB to load stored personal data.
+ $erasure_enabled = wc_string_to_bool( get_option( 'woocommerce_erasure_request_removes_order_data', 'no' ) );
+ $response = array(
+ 'items_removed' => false,
+ 'items_retained' => false,
+ 'messages' => array(),
+ 'done' => true,
+ );
+
+ $order_query = array(
+ 'limit' => 10,
+ 'page' => $page,
+ 'customer' => array( $email_address ),
+ );
+
+ if ( $user instanceof WP_User ) {
+ $order_query['customer'][] = (int) $user->ID;
+ }
+
+ $orders = wc_get_orders( $order_query );
+
+ if ( 0 < count( $orders ) ) {
+ foreach ( $orders as $order ) {
+ if ( apply_filters( 'woocommerce_privacy_erase_order_personal_data', $erasure_enabled, $order ) ) {
+ self::remove_order_personal_data( $order );
+
+ /* Translators: %s Order number. */
+ $response['messages'][] = sprintf( __( 'Removed personal data from order %s.', 'woocommerce' ), $order->get_order_number() );
+ $response['items_removed'] = true;
+ } else {
+ /* Translators: %s Order number. */
+ $response['messages'][] = sprintf( __( 'Personal data within order %s has been retained.', 'woocommerce' ), $order->get_order_number() );
+ $response['items_retained'] = true;
+ }
+ }
+ $response['done'] = 10 > count( $orders );
+ } else {
+ $response['done'] = true;
+ }
+
+ return $response;
+ }
+
+ /**
+ * Finds and removes customer download logs by email address.
+ *
+ * @since 3.4.0
+ * @param string $email_address The user email address.
+ * @param int $page Page.
+ * @return array An array of personal data in name value pairs
+ */
+ public static function download_data_eraser( $email_address, $page ) {
+ $page = (int) $page;
+ $user = get_user_by( 'email', $email_address ); // Check if user has an ID in the DB to load stored personal data.
+ $erasure_enabled = wc_string_to_bool( get_option( 'woocommerce_erasure_request_removes_download_data', 'no' ) );
+ $response = array(
+ 'items_removed' => false,
+ 'items_retained' => false,
+ 'messages' => array(),
+ 'done' => true,
+ );
+
+ $downloads_query = array(
+ 'limit' => -1,
+ 'page' => $page,
+ 'return' => 'ids',
+ );
+
+ if ( $user instanceof WP_User ) {
+ $downloads_query['user_id'] = (int) $user->ID;
+ } else {
+ $downloads_query['user_email'] = $email_address;
+ }
+
+ $customer_download_data_store = WC_Data_Store::load( 'customer-download' );
+
+ // Revoke download permissions.
+ if ( apply_filters( 'woocommerce_privacy_erase_download_personal_data', $erasure_enabled, $email_address ) ) {
+ if ( $user instanceof WP_User ) {
+ $result = $customer_download_data_store->delete_by_user_id( (int) $user->ID );
+ } else {
+ $result = $customer_download_data_store->delete_by_user_email( $email_address );
+ }
+ if ( $result ) {
+ $response['messages'][] = __( 'Removed access to downloadable files.', 'woocommerce' );
+ $response['items_removed'] = true;
+ }
+ } else {
+ $response['messages'][] = __( 'Customer download permissions have been retained.', 'woocommerce' );
+ $response['items_retained'] = true;
+ }
+
+ return $response;
+ }
+
+ /**
+ * Remove personal data specific to WooCommerce from an order object.
+ *
+ * Note; this will hinder order processing for obvious reasons!
+ *
+ * @param WC_Order $order Order object.
+ */
+ public static function remove_order_personal_data( $order ) {
+ $anonymized_data = array();
+
+ /**
+ * Allow extensions to remove their own personal data for this order first, so order data is still available.
+ *
+ * @since 3.4.0
+ * @param WC_Order $order A customer object.
+ */
+ do_action( 'woocommerce_privacy_before_remove_order_personal_data', $order );
+
+ /**
+ * Expose props and data types we'll be anonymizing.
+ *
+ * @since 3.4.0
+ * @param array $props Keys are the prop names, values are the data type we'll be passing to wp_privacy_anonymize_data().
+ * @param WC_Order $order A customer object.
+ */
+ $props_to_remove = apply_filters(
+ 'woocommerce_privacy_remove_order_personal_data_props',
+ array(
+ 'customer_ip_address' => 'ip',
+ 'customer_user_agent' => 'text',
+ 'billing_first_name' => 'text',
+ 'billing_last_name' => 'text',
+ 'billing_company' => 'text',
+ 'billing_address_1' => 'text',
+ 'billing_address_2' => 'text',
+ 'billing_city' => 'text',
+ 'billing_postcode' => 'text',
+ 'billing_state' => 'address_state',
+ 'billing_country' => 'address_country',
+ 'billing_phone' => 'phone',
+ 'billing_email' => 'email',
+ 'shipping_first_name' => 'text',
+ 'shipping_last_name' => 'text',
+ 'shipping_company' => 'text',
+ 'shipping_address_1' => 'text',
+ 'shipping_address_2' => 'text',
+ 'shipping_city' => 'text',
+ 'shipping_postcode' => 'text',
+ 'shipping_state' => 'address_state',
+ 'shipping_country' => 'address_country',
+ 'customer_id' => 'numeric_id',
+ 'transaction_id' => 'numeric_id',
+ ),
+ $order
+ );
+
+ if ( ! empty( $props_to_remove ) && is_array( $props_to_remove ) ) {
+ foreach ( $props_to_remove as $prop => $data_type ) {
+ // Get the current value in edit context.
+ $value = $order->{"get_$prop"}( 'edit' );
+
+ // If the value is empty, it does not need to be anonymized.
+ if ( empty( $value ) || empty( $data_type ) ) {
+ continue;
+ }
+
+ $anon_value = function_exists( 'wp_privacy_anonymize_data' ) ? wp_privacy_anonymize_data( $data_type, $value ) : '';
+
+ /**
+ * Expose a way to control the anonymized value of a prop via 3rd party code.
+ *
+ * @since 3.4.0
+ * @param string $anon_value Value of this prop after anonymization.
+ * @param string $prop Name of the prop being removed.
+ * @param string $value Current value of the data.
+ * @param string $data_type Type of data.
+ * @param WC_Order $order An order object.
+ */
+ $anonymized_data[ $prop ] = apply_filters( 'woocommerce_privacy_remove_order_personal_data_prop_value', $anon_value, $prop, $value, $data_type, $order );
+ }
+ }
+
+ // Set all new props and persist the new data to the database.
+ $order->set_props( $anonymized_data );
+
+ // Remove meta data.
+ $meta_to_remove = apply_filters(
+ 'woocommerce_privacy_remove_order_personal_data_meta',
+ array(
+ 'Payer first name' => 'text',
+ 'Payer last name' => 'text',
+ 'Payer PayPal address' => 'email',
+ 'Transaction ID' => 'numeric_id',
+ )
+ );
+
+ if ( ! empty( $meta_to_remove ) && is_array( $meta_to_remove ) ) {
+ foreach ( $meta_to_remove as $meta_key => $data_type ) {
+ $value = $order->get_meta( $meta_key );
+
+ // If the value is empty, it does not need to be anonymized.
+ if ( empty( $value ) || empty( $data_type ) ) {
+ continue;
+ }
+
+ $anon_value = function_exists( 'wp_privacy_anonymize_data' ) ? wp_privacy_anonymize_data( $data_type, $value ) : '';
+
+ /**
+ * Expose a way to control the anonymized value of a value via 3rd party code.
+ *
+ * @since 3.4.0
+ * @param string $anon_value Value of this data after anonymization.
+ * @param string $prop meta_key key being removed.
+ * @param string $value Current value of the data.
+ * @param string $data_type Type of data.
+ * @param WC_Order $order An order object.
+ */
+ $anon_value = apply_filters( 'woocommerce_privacy_remove_order_personal_data_meta_value', $anon_value, $meta_key, $value, $data_type, $order );
+
+ if ( $anon_value ) {
+ $order->update_meta_data( $meta_key, $anon_value );
+ } else {
+ $order->delete_meta_data( $meta_key );
+ }
+ }
+ }
+
+ $order->update_meta_data( '_anonymized', 'yes' );
+ $order->save();
+
+ // Delete order notes which can contain PII.
+ $notes = wc_get_order_notes(
+ array(
+ 'order_id' => $order->get_id(),
+ )
+ );
+
+ foreach ( $notes as $note ) {
+ wc_delete_order_note( $note->id );
+ }
+
+ // Add note that this event occured.
+ $order->add_order_note( __( 'Personal data removed.', 'woocommerce' ) );
+
+ /**
+ * Allow extensions to remove their own personal data for this order.
+ *
+ * @since 3.4.0
+ * @param WC_Order $order A customer object.
+ */
+ do_action( 'woocommerce_privacy_remove_order_personal_data', $order );
+ }
+
+ /**
+ * Finds and erases customer tokens by email address.
+ *
+ * @since 3.4.0
+ * @param string $email_address The user email address.
+ * @param int $page Page.
+ * @return array An array of personal data in name value pairs
+ */
+ public static function customer_tokens_eraser( $email_address, $page ) {
+ $response = array(
+ 'items_removed' => false,
+ 'items_retained' => false,
+ 'messages' => array(),
+ 'done' => true,
+ );
+
+ $user = get_user_by( 'email', $email_address ); // Check if user has an ID in the DB to load stored personal data.
+
+ if ( ! $user instanceof WP_User ) {
+ return $response;
+ }
+
+ $tokens = WC_Payment_Tokens::get_tokens(
+ array(
+ 'user_id' => $user->ID,
+ )
+ );
+
+ if ( empty( $tokens ) ) {
+ return $response;
+ }
+
+ foreach ( $tokens as $token ) {
+ WC_Payment_Tokens::delete( $token->get_id() );
+
+ /* Translators: %s Prop name. */
+ $response['messages'][] = sprintf( __( 'Removed payment token "%d"', 'woocommerce' ), $token->get_id() );
+ $response['items_removed'] = true;
+ }
+
+ /**
+ * Allow extensions to remove data for tokens and adjust the response.
+ *
+ * @since 3.4.0
+ * @param array $response Array resonse data. Must include messages, num_items_removed, num_items_retained, done.
+ * @param array $tokens Array of tokens.
+ */
+ return apply_filters( 'woocommerce_privacy_erase_personal_data_tokens', $response, $tokens );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-privacy-exporters.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-privacy-exporters.php
new file mode 100644
index 0000000..b248de8
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-privacy-exporters.php
@@ -0,0 +1,442 @@
+ 'woocommerce_customer',
+ 'group_label' => __( 'Customer Data', 'woocommerce' ),
+ 'group_description' => __( 'User’s WooCommerce customer data.', 'woocommerce' ),
+ 'item_id' => 'user',
+ 'data' => $customer_personal_data,
+ );
+ }
+ }
+
+ return array(
+ 'data' => $data_to_export,
+ 'done' => true,
+ );
+ }
+
+ /**
+ * Finds and exports data which could be used to identify a person from WooCommerce data associated with an email address.
+ *
+ * Orders are exported in blocks of 10 to avoid timeouts.
+ *
+ * @since 3.4.0
+ * @param string $email_address The user email address.
+ * @param int $page Page.
+ * @return array An array of personal data in name value pairs
+ */
+ public static function order_data_exporter( $email_address, $page ) {
+ $done = true;
+ $page = (int) $page;
+ $user = get_user_by( 'email', $email_address ); // Check if user has an ID in the DB to load stored personal data.
+ $data_to_export = array();
+ $order_query = array(
+ 'limit' => 10,
+ 'page' => $page,
+ 'customer' => array( $email_address ),
+ );
+
+ if ( $user instanceof WP_User ) {
+ $order_query['customer'][] = (int) $user->ID;
+ }
+
+ $orders = wc_get_orders( $order_query );
+
+ if ( 0 < count( $orders ) ) {
+ foreach ( $orders as $order ) {
+ $data_to_export[] = array(
+ 'group_id' => 'woocommerce_orders',
+ 'group_label' => __( 'Orders', 'woocommerce' ),
+ 'group_description' => __( 'User’s WooCommerce orders data.', 'woocommerce' ),
+ 'item_id' => 'order-' . $order->get_id(),
+ 'data' => self::get_order_personal_data( $order ),
+ );
+ }
+ $done = 10 > count( $orders );
+ }
+
+ return array(
+ 'data' => $data_to_export,
+ 'done' => $done,
+ );
+ }
+
+ /**
+ * Finds and exports customer download logs by email address.
+ *
+ * @since 3.4.0
+ * @param string $email_address The user email address.
+ * @param int $page Page.
+ * @throws Exception When WC_Data_Store validation fails.
+ * @return array An array of personal data in name value pairs
+ */
+ public static function download_data_exporter( $email_address, $page ) {
+ $done = true;
+ $page = (int) $page;
+ $user = get_user_by( 'email', $email_address ); // Check if user has an ID in the DB to load stored personal data.
+ $data_to_export = array();
+ $downloads_query = array(
+ 'limit' => 10,
+ 'page' => $page,
+ );
+
+ if ( $user instanceof WP_User ) {
+ $downloads_query['user_id'] = (int) $user->ID;
+ } else {
+ $downloads_query['user_email'] = $email_address;
+ }
+
+ $customer_download_data_store = WC_Data_Store::load( 'customer-download' );
+ $customer_download_log_data_store = WC_Data_Store::load( 'customer-download-log' );
+ $downloads = $customer_download_data_store->get_downloads( $downloads_query );
+
+ if ( 0 < count( $downloads ) ) {
+ foreach ( $downloads as $download ) {
+ $data_to_export[] = array(
+ 'group_id' => 'woocommerce_downloads',
+ /* translators: This is the headline for a list of downloads purchased from the store for a given user. */
+ 'group_label' => __( 'Purchased Downloads', 'woocommerce' ),
+ 'group_description' => __( 'User’s WooCommerce purchased downloads data.', 'woocommerce' ),
+ 'item_id' => 'download-' . $download->get_id(),
+ 'data' => self::get_download_personal_data( $download ),
+ );
+
+ $download_logs = $customer_download_log_data_store->get_download_logs_for_permission( $download->get_id() );
+
+ foreach ( $download_logs as $download_log ) {
+ $data_to_export[] = array(
+ 'group_id' => 'woocommerce_download_logs',
+ /* translators: This is the headline for a list of access logs for downloads purchased from the store for a given user. */
+ 'group_label' => __( 'Access to Purchased Downloads', 'woocommerce' ),
+ 'group_description' => __( 'User’s WooCommerce access to purchased downloads data.', 'woocommerce' ),
+ 'item_id' => 'download-log-' . $download_log->get_id(),
+ 'data' => array(
+ array(
+ 'name' => __( 'Download ID', 'woocommerce' ),
+ 'value' => $download_log->get_permission_id(),
+ ),
+ array(
+ 'name' => __( 'Timestamp', 'woocommerce' ),
+ 'value' => $download_log->get_timestamp(),
+ ),
+ array(
+ 'name' => __( 'IP Address', 'woocommerce' ),
+ 'value' => $download_log->get_user_ip_address(),
+ ),
+ ),
+ );
+ }
+ }
+ $done = 10 > count( $downloads );
+ }
+
+ return array(
+ 'data' => $data_to_export,
+ 'done' => $done,
+ );
+ }
+
+ /**
+ * Get personal data (key/value pairs) for a user object.
+ *
+ * @since 3.4.0
+ * @param WP_User $user user object.
+ * @throws Exception If customer cannot be read/found and $data is set to WC_Customer class.
+ * @return array
+ */
+ protected static function get_customer_personal_data( $user ) {
+ $personal_data = array();
+ $customer = new WC_Customer( $user->ID );
+
+ if ( ! $customer ) {
+ return array();
+ }
+
+ $props_to_export = apply_filters(
+ 'woocommerce_privacy_export_customer_personal_data_props',
+ array(
+ 'billing_first_name' => __( 'Billing First Name', 'woocommerce' ),
+ 'billing_last_name' => __( 'Billing Last Name', 'woocommerce' ),
+ 'billing_company' => __( 'Billing Company', 'woocommerce' ),
+ 'billing_address_1' => __( 'Billing Address 1', 'woocommerce' ),
+ 'billing_address_2' => __( 'Billing Address 2', 'woocommerce' ),
+ 'billing_city' => __( 'Billing City', 'woocommerce' ),
+ 'billing_postcode' => __( 'Billing Postal/Zip Code', 'woocommerce' ),
+ 'billing_state' => __( 'Billing State', 'woocommerce' ),
+ 'billing_country' => __( 'Billing Country / Region', 'woocommerce' ),
+ 'billing_phone' => __( 'Phone Number', 'woocommerce' ),
+ 'billing_email' => __( 'Email Address', 'woocommerce' ),
+ 'shipping_first_name' => __( 'Shipping First Name', 'woocommerce' ),
+ 'shipping_last_name' => __( 'Shipping Last Name', 'woocommerce' ),
+ 'shipping_company' => __( 'Shipping Company', 'woocommerce' ),
+ 'shipping_address_1' => __( 'Shipping Address 1', 'woocommerce' ),
+ 'shipping_address_2' => __( 'Shipping Address 2', 'woocommerce' ),
+ 'shipping_city' => __( 'Shipping City', 'woocommerce' ),
+ 'shipping_postcode' => __( 'Shipping Postal/Zip Code', 'woocommerce' ),
+ 'shipping_state' => __( 'Shipping State', 'woocommerce' ),
+ 'shipping_country' => __( 'Shipping Country / Region', 'woocommerce' ),
+ ),
+ $customer
+ );
+
+ foreach ( $props_to_export as $prop => $description ) {
+ $value = '';
+
+ if ( is_callable( array( $customer, 'get_' . $prop ) ) ) {
+ $value = $customer->{"get_$prop"}( 'edit' );
+ }
+
+ $value = apply_filters( 'woocommerce_privacy_export_customer_personal_data_prop_value', $value, $prop, $customer );
+
+ if ( $value ) {
+ $personal_data[] = array(
+ 'name' => $description,
+ 'value' => $value,
+ );
+ }
+ }
+
+ /**
+ * Allow extensions to register their own personal data for this customer for the export.
+ *
+ * @since 3.4.0
+ * @param array $personal_data Array of name value pairs.
+ * @param WC_Order $order A customer object.
+ */
+ $personal_data = apply_filters( 'woocommerce_privacy_export_customer_personal_data', $personal_data, $customer );
+
+ return $personal_data;
+ }
+
+ /**
+ * Get personal data (key/value pairs) for an order object.
+ *
+ * @since 3.4.0
+ * @param WC_Order $order Order object.
+ * @return array
+ */
+ protected static function get_order_personal_data( $order ) {
+ $personal_data = array();
+ $props_to_export = apply_filters(
+ 'woocommerce_privacy_export_order_personal_data_props',
+ array(
+ 'order_number' => __( 'Order Number', 'woocommerce' ),
+ 'date_created' => __( 'Order Date', 'woocommerce' ),
+ 'total' => __( 'Order Total', 'woocommerce' ),
+ 'items' => __( 'Items Purchased', 'woocommerce' ),
+ 'customer_ip_address' => __( 'IP Address', 'woocommerce' ),
+ 'customer_user_agent' => __( 'Browser User Agent', 'woocommerce' ),
+ 'formatted_billing_address' => __( 'Billing Address', 'woocommerce' ),
+ 'formatted_shipping_address' => __( 'Shipping Address', 'woocommerce' ),
+ 'billing_phone' => __( 'Phone Number', 'woocommerce' ),
+ 'billing_email' => __( 'Email Address', 'woocommerce' ),
+ ),
+ $order
+ );
+
+ foreach ( $props_to_export as $prop => $name ) {
+ $value = '';
+
+ switch ( $prop ) {
+ case 'items':
+ $item_names = array();
+ foreach ( $order->get_items() as $item ) {
+ $item_names[] = $item->get_name() . ' x ' . $item->get_quantity();
+ }
+ $value = implode( ', ', $item_names );
+ break;
+ case 'date_created':
+ $value = wc_format_datetime( $order->get_date_created(), get_option( 'date_format' ) . ', ' . get_option( 'time_format' ) );
+ break;
+ case 'formatted_billing_address':
+ case 'formatted_shipping_address':
+ $value = preg_replace( '#
#i', ', ', $order->{"get_$prop"}() );
+ break;
+ default:
+ if ( is_callable( array( $order, 'get_' . $prop ) ) ) {
+ $value = $order->{"get_$prop"}();
+ }
+ break;
+ }
+
+ $value = apply_filters( 'woocommerce_privacy_export_order_personal_data_prop', $value, $prop, $order );
+
+ if ( $value ) {
+ $personal_data[] = array(
+ 'name' => $name,
+ 'value' => $value,
+ );
+ }
+ }
+
+ // Export meta data.
+ $meta_to_export = apply_filters(
+ 'woocommerce_privacy_export_order_personal_data_meta',
+ array(
+ 'Payer first name' => __( 'Payer first name', 'woocommerce' ),
+ 'Payer last name' => __( 'Payer last name', 'woocommerce' ),
+ 'Payer PayPal address' => __( 'Payer PayPal address', 'woocommerce' ),
+ 'Transaction ID' => __( 'Transaction ID', 'woocommerce' ),
+ )
+ );
+
+ if ( ! empty( $meta_to_export ) && is_array( $meta_to_export ) ) {
+ foreach ( $meta_to_export as $meta_key => $name ) {
+ $value = apply_filters( 'woocommerce_privacy_export_order_personal_data_meta_value', $order->get_meta( $meta_key ), $meta_key, $order );
+
+ if ( $value ) {
+ $personal_data[] = array(
+ 'name' => $name,
+ 'value' => $value,
+ );
+ }
+ }
+ }
+
+ /**
+ * Allow extensions to register their own personal data for this order for the export.
+ *
+ * @since 3.4.0
+ * @param array $personal_data Array of name value pairs to expose in the export.
+ * @param WC_Order $order An order object.
+ */
+ $personal_data = apply_filters( 'woocommerce_privacy_export_order_personal_data', $personal_data, $order );
+
+ return $personal_data;
+ }
+
+ /**
+ * Get personal data (key/value pairs) for a download object.
+ *
+ * @since 3.4.0
+ * @param WC_Order $download Download object.
+ * @return array
+ */
+ protected static function get_download_personal_data( $download ) {
+ $personal_data = array(
+ array(
+ 'name' => __( 'Download ID', 'woocommerce' ),
+ 'value' => $download->get_id(),
+ ),
+ array(
+ 'name' => __( 'Order ID', 'woocommerce' ),
+ 'value' => $download->get_order_id(),
+ ),
+ array(
+ 'name' => __( 'Product', 'woocommerce' ),
+ 'value' => get_the_title( $download->get_product_id() ),
+ ),
+ array(
+ 'name' => __( 'User email', 'woocommerce' ),
+ 'value' => $download->get_user_email(),
+ ),
+ array(
+ 'name' => __( 'Downloads remaining', 'woocommerce' ),
+ 'value' => $download->get_downloads_remaining(),
+ ),
+ array(
+ 'name' => __( 'Download count', 'woocommerce' ),
+ 'value' => $download->get_download_count(),
+ ),
+ array(
+ 'name' => __( 'Access granted', 'woocommerce' ),
+ 'value' => date( 'Y-m-d', $download->get_access_granted( 'edit' )->getTimestamp() ),
+ ),
+ array(
+ 'name' => __( 'Access expires', 'woocommerce' ),
+ 'value' => ! is_null( $download->get_access_expires( 'edit' ) ) ? date( 'Y-m-d', $download->get_access_expires( 'edit' )->getTimestamp() ) : null,
+ ),
+ );
+
+ /**
+ * Allow extensions to register their own personal data for this download for the export.
+ *
+ * @since 3.4.0
+ * @param array $personal_data Array of name value pairs to expose in the export.
+ * @param WC_Order $order An order object.
+ */
+ $personal_data = apply_filters( 'woocommerce_privacy_export_download_personal_data', $personal_data, $download );
+
+ return $personal_data;
+ }
+
+ /**
+ * Finds and exports payment tokens by email address for a customer.
+ *
+ * @since 3.4.0
+ * @param string $email_address The user email address.
+ * @param int $page Page.
+ * @return array An array of personal data in name value pairs
+ */
+ public static function customer_tokens_exporter( $email_address, $page ) {
+ $user = get_user_by( 'email', $email_address ); // Check if user has an ID in the DB to load stored personal data.
+ $data_to_export = array();
+
+ if ( ! $user instanceof WP_User ) {
+ return array(
+ 'data' => $data_to_export,
+ 'done' => true,
+ );
+ }
+
+ $tokens = WC_Payment_Tokens::get_tokens(
+ array(
+ 'user_id' => $user->ID,
+ 'limit' => 10,
+ 'page' => $page,
+ )
+ );
+
+ if ( 0 < count( $tokens ) ) {
+ foreach ( $tokens as $token ) {
+ $data_to_export[] = array(
+ 'group_id' => 'woocommerce_tokens',
+ 'group_label' => __( 'Payment Tokens', 'woocommerce' ),
+ 'group_description' => __( 'User’s WooCommerce payment tokens data.', 'woocommerce' ),
+ 'item_id' => 'token-' . $token->get_id(),
+ 'data' => array(
+ array(
+ 'name' => __( 'Token', 'woocommerce' ),
+ 'value' => $token->get_display_name(),
+ ),
+ ),
+ );
+ }
+ $done = 10 > count( $tokens );
+ } else {
+ $done = true;
+ }
+
+ return array(
+ 'data' => $data_to_export,
+ 'done' => $done,
+ );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-privacy.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-privacy.php
new file mode 100644
index 0000000..f9e3dbf
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-privacy.php
@@ -0,0 +1,381 @@
+add_exporter( 'woocommerce-customer-data', __( 'WooCommerce Customer Data', 'woocommerce' ), array( 'WC_Privacy_Exporters', 'customer_data_exporter' ) );
+ $this->add_exporter( 'woocommerce-customer-orders', __( 'WooCommerce Customer Orders', 'woocommerce' ), array( 'WC_Privacy_Exporters', 'order_data_exporter' ) );
+ $this->add_exporter( 'woocommerce-customer-downloads', __( 'WooCommerce Customer Downloads', 'woocommerce' ), array( 'WC_Privacy_Exporters', 'download_data_exporter' ) );
+ $this->add_exporter( 'woocommerce-customer-tokens', __( 'WooCommerce Customer Payment Tokens', 'woocommerce' ), array( 'WC_Privacy_Exporters', 'customer_tokens_exporter' ) );
+
+ // This hook registers WooCommerce data erasers.
+ $this->add_eraser( 'woocommerce-customer-data', __( 'WooCommerce Customer Data', 'woocommerce' ), array( 'WC_Privacy_Erasers', 'customer_data_eraser' ) );
+ $this->add_eraser( 'woocommerce-customer-orders', __( 'WooCommerce Customer Orders', 'woocommerce' ), array( 'WC_Privacy_Erasers', 'order_data_eraser' ) );
+ $this->add_eraser( 'woocommerce-customer-downloads', __( 'WooCommerce Customer Downloads', 'woocommerce' ), array( 'WC_Privacy_Erasers', 'download_data_eraser' ) );
+ $this->add_eraser( 'woocommerce-customer-tokens', __( 'WooCommerce Customer Payment Tokens', 'woocommerce' ), array( 'WC_Privacy_Erasers', 'customer_tokens_eraser' ) );
+
+ // Cleanup orders daily - this is a callback on a daily cron event.
+ add_action( 'woocommerce_cleanup_personal_data', array( $this, 'queue_cleanup_personal_data' ) );
+
+ // Handles custom anonomization types not included in core.
+ add_filter( 'wp_privacy_anonymize_data', array( $this, 'anonymize_custom_data_types' ), 10, 3 );
+
+ // When this is fired, data is removed in a given order. Called from bulk actions.
+ add_action( 'woocommerce_remove_order_personal_data', array( 'WC_Privacy_Erasers', 'remove_order_personal_data' ) );
+ }
+
+ /**
+ * Add privacy policy content for the privacy policy page.
+ *
+ * @since 3.4.0
+ */
+ public function get_privacy_message() {
+ $content = '
' . + __( 'This sample language includes the basics around what personal data your store may be collecting, storing and sharing, as well as who may have access to that data. Depending on what settings are enabled and which additional plugins are used, the specific information shared by your store will vary. We recommend consulting with a lawyer when deciding what information to disclose on your privacy policy.', 'woocommerce' ) . + '
' . + '' . __( 'We collect information about you during the checkout process on our store.', 'woocommerce' ) . '
' . + '' . __( 'While you visit our site, we’ll track:', 'woocommerce' ) . '
' . + '' . __( 'We’ll also use cookies to keep track of cart contents while you’re browsing our site.', 'woocommerce' ) . '
' . + '' . + __( 'Note: you may want to further detail your cookie policy, and link to that section from here.', 'woocommerce' ) . + '
' . + '' . __( 'When you purchase from us, we’ll ask you to provide information including your name, billing address, shipping address, email address, phone number, credit card/payment details and optional account information like username and password. We’ll use this information for purposes, such as, to:', 'woocommerce' ) . '
' . + '' . __( 'If you create an account, we will store your name, address, email and phone number, which will be used to populate the checkout for future orders.', 'woocommerce' ) . '
' . + '' . __( 'We generally store information about you for as long as we need the information for the purposes for which we collect and use it, and we are not legally required to continue to keep it. For example, we will store order information for XXX years for tax and accounting purposes. This includes your name, email address and billing and shipping addresses.', 'woocommerce' ) . '
' . + '' . __( 'We will also store comments or reviews, if you choose to leave them.', 'woocommerce' ) . '
' . + '' . __( 'Members of our team have access to the information you provide us. For example, both Administrators and Shop Managers can access:', 'woocommerce' ) . '
' . + '' . __( 'Our team members have access to this information to help fulfill orders, process refunds and support you.', 'woocommerce' ) . '
' . + '' . + __( 'In this section you should list who you’re sharing data with, and for what purpose. This could include, but may not be limited to, analytics, marketing, payment gateways, shipping providers, and third party embeds.', 'woocommerce' ) . + '
' . + '' . __( 'We share information with third parties who help us provide our orders and store services to you; for example --', 'woocommerce' ) . '
' . + '' . + __( 'In this subsection you should list which third party payment processors you’re using to take payments on your store since these may handle customer data. We’ve included PayPal as an example, but you should remove this if you’re not using PayPal.', 'woocommerce' ) . + '
' . + '' . __( 'We accept payments through PayPal. When processing payments, some of your data will be passed to PayPal, including information required to process or support the payment, such as the purchase total and billing information.', 'woocommerce' ) . '
' . + '' . __( 'Please see the PayPal Privacy Policy for more details.', 'woocommerce' ) . '
' . + ''; + + return apply_filters( 'wc_privacy_policy_content', $content ); + } + + /** + * Spawn events for order cleanup. + */ + public function queue_cleanup_personal_data() { + self::$background_process->push_to_queue( array( 'task' => 'trash_pending_orders' ) ); + self::$background_process->push_to_queue( array( 'task' => 'trash_failed_orders' ) ); + self::$background_process->push_to_queue( array( 'task' => 'trash_cancelled_orders' ) ); + self::$background_process->push_to_queue( array( 'task' => 'anonymize_completed_orders' ) ); + self::$background_process->push_to_queue( array( 'task' => 'delete_inactive_accounts' ) ); + self::$background_process->save()->dispatch(); + } + + /** + * Handle some custom types of data and anonymize them. + * + * @param string $anonymous Anonymized string. + * @param string $type Type of data. + * @param string $data The data being anonymized. + * @return string Anonymized string. + */ + public function anonymize_custom_data_types( $anonymous, $type, $data ) { + switch ( $type ) { + case 'address_state': + case 'address_country': + $anonymous = ''; // Empty string - we don't want to store anything after removal. + break; + case 'phone': + $anonymous = preg_replace( '/\d/u', '0', $data ); + break; + case 'numeric_id': + $anonymous = 0; + break; + } + return $anonymous; + } + + /** + * Find and trash old orders. + * + * @since 3.4.0 + * @param int $limit Limit orders to process per batch. + * @return int Number of orders processed. + */ + public static function trash_pending_orders( $limit = 20 ) { + $option = wc_parse_relative_date_option( get_option( 'woocommerce_trash_pending_orders' ) ); + + if ( empty( $option['number'] ) ) { + return 0; + } + + return self::trash_orders_query( + apply_filters( + 'woocommerce_trash_pending_orders_query_args', + array( + 'date_created' => '<' . strtotime( '-' . $option['number'] . ' ' . $option['unit'] ), + 'limit' => $limit, // Batches of 20. + 'status' => 'wc-pending', + 'type' => 'shop_order', + ) + ) + ); + } + + /** + * Find and trash old orders. + * + * @since 3.4.0 + * @param int $limit Limit orders to process per batch. + * @return int Number of orders processed. + */ + public static function trash_failed_orders( $limit = 20 ) { + $option = wc_parse_relative_date_option( get_option( 'woocommerce_trash_failed_orders' ) ); + + if ( empty( $option['number'] ) ) { + return 0; + } + + return self::trash_orders_query( + apply_filters( + 'woocommerce_trash_failed_orders_query_args', + array( + 'date_created' => '<' . strtotime( '-' . $option['number'] . ' ' . $option['unit'] ), + 'limit' => $limit, // Batches of 20. + 'status' => 'wc-failed', + 'type' => 'shop_order', + ) + ) + ); + } + + /** + * Find and trash old orders. + * + * @since 3.4.0 + * @param int $limit Limit orders to process per batch. + * @return int Number of orders processed. + */ + public static function trash_cancelled_orders( $limit = 20 ) { + $option = wc_parse_relative_date_option( get_option( 'woocommerce_trash_cancelled_orders' ) ); + + if ( empty( $option['number'] ) ) { + return 0; + } + + return self::trash_orders_query( + apply_filters( + 'woocommerce_trash_cancelled_orders_query_args', + array( + 'date_created' => '<' . strtotime( '-' . $option['number'] . ' ' . $option['unit'] ), + 'limit' => $limit, // Batches of 20. + 'status' => 'wc-cancelled', + 'type' => 'shop_order', + ) + ) + ); + } + + /** + * For a given query trash all matches. + * + * @since 3.4.0 + * @param array $query Query array to pass to wc_get_orders(). + * @return int Count of orders that were trashed. + */ + protected static function trash_orders_query( $query ) { + $orders = wc_get_orders( $query ); + $count = 0; + + if ( $orders ) { + foreach ( $orders as $order ) { + $order->delete( false ); + $count ++; + } + } + + return $count; + } + + /** + * Anonymize old completed orders. + * + * @since 3.4.0 + * @param int $limit Limit orders to process per batch. + * @return int Number of orders processed. + */ + public static function anonymize_completed_orders( $limit = 20 ) { + $option = wc_parse_relative_date_option( get_option( 'woocommerce_anonymize_completed_orders' ) ); + + if ( empty( $option['number'] ) ) { + return 0; + } + + return self::anonymize_orders_query( + apply_filters( + 'woocommerce_anonymize_completed_orders_query_args', + array( + 'date_created' => '<' . strtotime( '-' . $option['number'] . ' ' . $option['unit'] ), + 'limit' => $limit, // Batches of 20. + 'status' => 'wc-completed', + 'anonymized' => false, + 'type' => 'shop_order', + ) + ) + ); + } + + /** + * For a given query, anonymize all matches. + * + * @since 3.4.0 + * @param array $query Query array to pass to wc_get_orders(). + * @return int Count of orders that were anonymized. + */ + protected static function anonymize_orders_query( $query ) { + $orders = wc_get_orders( $query ); + $count = 0; + + if ( $orders ) { + foreach ( $orders as $order ) { + WC_Privacy_Erasers::remove_order_personal_data( $order ); + $count ++; + } + } + + return $count; + } + + /** + * Delete inactive accounts. + * + * @since 3.4.0 + * @param int $limit Limit users to process per batch. + * @return int Number of users processed. + */ + public static function delete_inactive_accounts( $limit = 20 ) { + $option = wc_parse_relative_date_option( get_option( 'woocommerce_delete_inactive_accounts' ) ); + + if ( empty( $option['number'] ) ) { + return 0; + } + + return self::delete_inactive_accounts_query( strtotime( '-' . $option['number'] . ' ' . $option['unit'] ), $limit ); + } + + /** + * Delete inactive accounts. + * + * @since 3.4.0 + * @param int $timestamp Timestamp to delete customers before. + * @param int $limit Limit number of users to delete per run. + * @return int Count of customers that were deleted. + */ + protected static function delete_inactive_accounts_query( $timestamp, $limit = 20 ) { + $count = 0; + $user_query = new WP_User_Query( + array( + 'fields' => 'ID', + 'number' => $limit, + 'role__in' => apply_filters( + 'woocommerce_delete_inactive_account_roles', + array( + 'Customer', + 'Subscriber', + ) + ), + 'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query + 'relation' => 'AND', + array( + 'key' => 'wc_last_active', + 'value' => (string) $timestamp, + 'compare' => '<', + 'type' => 'NUMERIC', + ), + array( + 'key' => 'wc_last_active', + 'value' => '0', + 'compare' => '>', + 'type' => 'NUMERIC', + ), + ), + ) + ); + + $user_ids = $user_query->get_results(); + + if ( $user_ids ) { + if ( ! function_exists( 'wp_delete_user' ) ) { + require_once ABSPATH . 'wp-admin/includes/user.php'; + } + + foreach ( $user_ids as $user_id ) { + wp_delete_user( $user_id ); + $count ++; + } + } + + return $count; + } +} + +new WC_Privacy(); diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-attribute.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-attribute.php new file mode 100644 index 0000000..14f1901 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-attribute.php @@ -0,0 +1,329 @@ + 0, + 'name' => '', + 'options' => array(), + 'position' => 0, + 'visible' => false, + 'variation' => false, + ); + + /** + * Return if this attribute is a taxonomy. + * + * @return boolean + */ + public function is_taxonomy() { + return 0 < $this->get_id(); + } + + /** + * Get taxonomy name if applicable. + * + * @return string + */ + public function get_taxonomy() { + return $this->is_taxonomy() ? $this->get_name() : ''; + } + + /** + * Get taxonomy object. + * + * @return array|null + */ + public function get_taxonomy_object() { + global $wc_product_attributes; + return $this->is_taxonomy() ? $wc_product_attributes[ $this->get_name() ] : null; + } + + /** + * Gets terms from the stored options. + * + * @return array|null + */ + public function get_terms() { + if ( ! $this->is_taxonomy() || ! taxonomy_exists( $this->get_name() ) ) { + return null; + } + $terms = array(); + foreach ( $this->get_options() as $option ) { + if ( is_int( $option ) ) { + $term = get_term_by( 'id', $option, $this->get_name() ); + } else { + // Term names get escaped in WP. See sanitize_term_field. + $term = get_term_by( 'name', $option, $this->get_name() ); + + if ( ! $term || is_wp_error( $term ) ) { + $new_term = wp_insert_term( $option, $this->get_name() ); + $term = is_wp_error( $new_term ) ? false : get_term_by( 'id', $new_term['term_id'], $this->get_name() ); + } + } + if ( $term && ! is_wp_error( $term ) ) { + $terms[] = $term; + } + } + return $terms; + } + + /** + * Gets slugs from the stored options, or just the string if text based. + * + * @return array + */ + public function get_slugs() { + if ( ! $this->is_taxonomy() || ! taxonomy_exists( $this->get_name() ) ) { + return $this->get_options(); + } + $terms = array(); + foreach ( $this->get_options() as $option ) { + if ( is_int( $option ) ) { + $term = get_term_by( 'id', $option, $this->get_name() ); + } else { + $term = get_term_by( 'name', $option, $this->get_name() ); + + if ( ! $term || is_wp_error( $term ) ) { + $new_term = wp_insert_term( $option, $this->get_name() ); + $term = is_wp_error( $new_term ) ? false : get_term_by( 'id', $new_term['term_id'], $this->get_name() ); + } + } + if ( $term && ! is_wp_error( $term ) ) { + $terms[] = $term->slug; + } + } + return $terms; + } + + /** + * Returns all data for this object. + * + * @return array + */ + public function get_data() { + return array_merge( + $this->data, + array( + 'is_visible' => $this->get_visible() ? 1 : 0, + 'is_variation' => $this->get_variation() ? 1 : 0, + 'is_taxonomy' => $this->is_taxonomy() ? 1 : 0, + 'value' => $this->is_taxonomy() ? '' : wc_implode_text_attributes( $this->get_options() ), + ) + ); + } + + /* + |-------------------------------------------------------------------------- + | Setters + |-------------------------------------------------------------------------- + */ + + /** + * Set ID (this is the attribute ID). + * + * @param int $value Attribute ID. + */ + public function set_id( $value ) { + $this->data['id'] = absint( $value ); + } + + /** + * Set name (this is the attribute name or taxonomy). + * + * @param int $value Attribute name. + */ + public function set_name( $value ) { + $this->data['name'] = $value; + } + + /** + * Set options. + * + * @param array $value Attribute options. + */ + public function set_options( $value ) { + $this->data['options'] = $value; + } + + /** + * Set position. + * + * @param int $value Attribute position. + */ + public function set_position( $value ) { + $this->data['position'] = absint( $value ); + } + + /** + * Set if visible. + * + * @param bool $value If is visible on Product's additional info tab. + */ + public function set_visible( $value ) { + $this->data['visible'] = wc_string_to_bool( $value ); + } + + /** + * Set if variation. + * + * @param bool $value If is used for variations. + */ + public function set_variation( $value ) { + $this->data['variation'] = wc_string_to_bool( $value ); + } + + /* + |-------------------------------------------------------------------------- + | Getters + |-------------------------------------------------------------------------- + */ + + /** + * Get the ID. + * + * @return int + */ + public function get_id() { + return $this->data['id']; + } + + /** + * Get name. + * + * @return string + */ + public function get_name() { + return $this->data['name']; + } + + /** + * Get options. + * + * @return array + */ + public function get_options() { + return $this->data['options']; + } + + /** + * Get position. + * + * @return int + */ + public function get_position() { + return $this->data['position']; + } + + /** + * Get if visible. + * + * @return bool + */ + public function get_visible() { + return $this->data['visible']; + } + + /** + * Get if variation. + * + * @return bool + */ + public function get_variation() { + return $this->data['variation']; + } + + /* + |-------------------------------------------------------------------------- + | ArrayAccess/Backwards compatibility. + |-------------------------------------------------------------------------- + */ + + /** + * OffsetGet. + * + * @param string $offset Offset. + * @return mixed + */ + public function offsetGet( $offset ) { + switch ( $offset ) { + case 'is_variation': + return $this->get_variation() ? 1 : 0; + case 'is_visible': + return $this->get_visible() ? 1 : 0; + case 'is_taxonomy': + return $this->is_taxonomy() ? 1 : 0; + case 'value': + return $this->is_taxonomy() ? '' : wc_implode_text_attributes( $this->get_options() ); + default: + if ( is_callable( array( $this, "get_$offset" ) ) ) { + return $this->{"get_$offset"}(); + } + break; + } + return ''; + } + + /** + * OffsetSet. + * + * @param string $offset Offset. + * @param mixed $value Value. + */ + public function offsetSet( $offset, $value ) { + switch ( $offset ) { + case 'is_variation': + $this->set_variation( $value ); + break; + case 'is_visible': + $this->set_visible( $value ); + break; + case 'value': + $this->set_options( $value ); + break; + default: + if ( is_callable( array( $this, "set_$offset" ) ) ) { + return $this->{"set_$offset"}( $value ); + } + break; + } + } + + /** + * OffsetUnset. + * + * @param string $offset Offset. + */ + public function offsetUnset( $offset ) {} + + /** + * OffsetExists. + * + * @param string $offset Offset. + * @return bool + */ + public function offsetExists( $offset ) { + return in_array( $offset, array_merge( array( 'is_variation', 'is_visible', 'is_taxonomy', 'value' ), array_keys( $this->data ) ), true ); + } +} diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-download.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-download.php new file mode 100644 index 0000000..1c13bf1 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-download.php @@ -0,0 +1,276 @@ + '', + 'name' => '', + 'file' => '', + ); + + /** + * Returns all data for this object. + * + * @return array + */ + public function get_data() { + return $this->data; + } + + /** + * Get allowed mime types. + * + * @return array + */ + public function get_allowed_mime_types() { + return apply_filters( 'woocommerce_downloadable_file_allowed_mime_types', get_allowed_mime_types() ); + } + + /** + * Get type of file path set. + * + * @param string $file_path optional. + * @return string absolute, relative, or shortcode. + */ + public function get_type_of_file_path( $file_path = '' ) { + $file_path = $file_path ? $file_path : $this->get_file(); + if ( 0 === strpos( $file_path, 'http' ) || 0 === strpos( $file_path, '//' ) ) { + return 'absolute'; + } elseif ( '[' === substr( $file_path, 0, 1 ) && ']' === substr( $file_path, -1 ) ) { + return 'shortcode'; + } else { + return 'relative'; + } + } + + /** + * Get file type. + * + * @return string + */ + public function get_file_type() { + $type = wp_check_filetype( strtok( $this->get_file(), '?' ), $this->get_allowed_mime_types() ); + return $type['type']; + } + + /** + * Get file extension. + * + * @return string + */ + public function get_file_extension() { + $parsed_url = wp_parse_url( $this->get_file(), PHP_URL_PATH ); + return pathinfo( $parsed_url, PATHINFO_EXTENSION ); + } + + /** + * Check if file is allowed. + * + * @return boolean + */ + public function is_allowed_filetype() { + $file_path = $this->get_file(); + + // File types for URL-based files located on the server should get validated. + $is_file_on_server = false; + if ( false !== stripos( $file_path, network_site_url( '/', 'https' ) ) || + false !== stripos( $file_path, network_site_url( '/', 'http' ) ) || + false !== stripos( $file_path, site_url( '/', 'https' ) ) || + false !== stripos( $file_path, site_url( '/', 'http' ) ) + ) { + $is_file_on_server = true; + } + + if ( ! $is_file_on_server && 'relative' !== $this->get_type_of_file_path() ) { + return true; + } + return ! $this->get_file_extension() || in_array( $this->get_file_type(), $this->get_allowed_mime_types(), true ); + } + + /** + * Validate file exists. + * + * @return boolean + */ + public function file_exists() { + if ( 'relative' !== $this->get_type_of_file_path() ) { + return true; + } + $file_url = $this->get_file(); + if ( '..' === substr( $file_url, 0, 2 ) || '/' !== substr( $file_url, 0, 1 ) ) { + $file_url = realpath( ABSPATH . $file_url ); + } elseif ( substr( WP_CONTENT_DIR, strlen( untrailingslashit( ABSPATH ) ) ) === substr( $file_url, 0, strlen( substr( WP_CONTENT_DIR, strlen( untrailingslashit( ABSPATH ) ) ) ) ) ) { + $file_url = realpath( WP_CONTENT_DIR . substr( $file_url, 11 ) ); + } + return apply_filters( 'woocommerce_downloadable_file_exists', file_exists( $file_url ), $this->get_file() ); + } + + /* + |-------------------------------------------------------------------------- + | Setters + |-------------------------------------------------------------------------- + */ + + /** + * Set ID. + * + * @param string $value Download ID. + */ + public function set_id( $value ) { + $this->data['id'] = wc_clean( $value ); + } + + /** + * Set name. + * + * @param string $value Download name. + */ + public function set_name( $value ) { + $this->data['name'] = wc_clean( $value ); + } + + /** + * Set previous_hash. + * + * @deprecated 3.3.0 No longer using filename based hashing to keep track of files. + * @param string $value Previous hash. + */ + public function set_previous_hash( $value ) { + wc_deprecated_function( __FUNCTION__, '3.3' ); + $this->data['previous_hash'] = wc_clean( $value ); + } + + /** + * Set file. + * + * @param string $value File URL/Path. + */ + public function set_file( $value ) { + switch ( $this->get_type_of_file_path( $value ) ) { + case 'absolute': + $this->data['file'] = esc_url_raw( $value ); + break; + default: + $this->data['file'] = wc_clean( $value ); + break; + } + } + + /* + |-------------------------------------------------------------------------- + | Getters + |-------------------------------------------------------------------------- + */ + + /** + * Get id. + * + * @return string + */ + public function get_id() { + return $this->data['id']; + } + + /** + * Get name. + * + * @return string + */ + public function get_name() { + return $this->data['name']; + } + + /** + * Get previous_hash. + * + * @deprecated 3.3.0 No longer using filename based hashing to keep track of files. + * @return string + */ + public function get_previous_hash() { + wc_deprecated_function( __FUNCTION__, '3.3' ); + return $this->data['previous_hash']; + } + + /** + * Get file. + * + * @return string + */ + public function get_file() { + return $this->data['file']; + } + + /* + |-------------------------------------------------------------------------- + | ArrayAccess/Backwards compatibility. + |-------------------------------------------------------------------------- + */ + + /** + * OffsetGet. + * + * @param string $offset Offset. + * @return mixed + */ + public function offsetGet( $offset ) { + switch ( $offset ) { + default: + if ( is_callable( array( $this, "get_$offset" ) ) ) { + return $this->{"get_$offset"}(); + } + break; + } + return ''; + } + + /** + * OffsetSet. + * + * @param string $offset Offset. + * @param mixed $value Offset value. + */ + public function offsetSet( $offset, $value ) { + switch ( $offset ) { + default: + if ( is_callable( array( $this, "set_$offset" ) ) ) { + return $this->{"set_$offset"}( $value ); + } + break; + } + } + + /** + * OffsetUnset. + * + * @param string $offset Offset. + */ + public function offsetUnset( $offset ) {} + + /** + * OffsetExists. + * + * @param string $offset Offset. + * @return bool + */ + public function offsetExists( $offset ) { + return in_array( $offset, array_keys( $this->data ), true ); + } +} diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-external.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-external.php new file mode 100644 index 0000000..f88d45f --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-external.php @@ -0,0 +1,194 @@ + '', + 'button_text' => '', + ); + + /** + * Get internal type. + * + * @return string + */ + public function get_type() { + return 'external'; + } + + /* + |-------------------------------------------------------------------------- + | Getters + |-------------------------------------------------------------------------- + | + | Methods for getting data from the product object. + */ + + /** + * Get product url. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_product_url( $context = 'view' ) { + return esc_url_raw( $this->get_prop( 'product_url', $context ) ); + } + + /** + * Get button text. + * + * @param string $context What the value is for. Valid values are 'view' and 'edit'. + * @return string + */ + public function get_button_text( $context = 'view' ) { + return $this->get_prop( 'button_text', $context ); + } + + /* + |-------------------------------------------------------------------------- + | Setters + |-------------------------------------------------------------------------- + | + | Functions for setting product data. These should not update anything in the + | database itself and should only change what is stored in the class + | object. + */ + + /** + * Set product URL. + * + * @since 3.0.0 + * @param string $product_url Product URL. + */ + public function set_product_url( $product_url ) { + $this->set_prop( 'product_url', htmlspecialchars_decode( $product_url ) ); + } + + /** + * Set button text. + * + * @since 3.0.0 + * @param string $button_text Button text. + */ + public function set_button_text( $button_text ) { + $this->set_prop( 'button_text', $button_text ); + } + + /** + * External products cannot be stock managed. + * + * @since 3.0.0 + * @param bool $manage_stock If manage stock. + */ + public function set_manage_stock( $manage_stock ) { + $this->set_prop( 'manage_stock', false ); + + if ( true === $manage_stock ) { + $this->error( 'product_external_invalid_manage_stock', __( 'External products cannot be stock managed.', 'woocommerce' ) ); + } + } + + /** + * External products cannot be stock managed. + * + * @since 3.0.0 + * + * @param string $stock_status Stock status. + */ + public function set_stock_status( $stock_status = '' ) { + $this->set_prop( 'stock_status', 'instock' ); + + if ( 'instock' !== $stock_status ) { + $this->error( 'product_external_invalid_stock_status', __( 'External products cannot be stock managed.', 'woocommerce' ) ); + } + } + + /** + * External products cannot be backordered. + * + * @since 3.0.0 + * @param string $backorders Options: 'yes', 'no' or 'notify'. + */ + public function set_backorders( $backorders ) { + $this->set_prop( 'backorders', 'no' ); + + if ( 'no' !== $backorders ) { + $this->error( 'product_external_invalid_backorders', __( 'External products cannot be backordered.', 'woocommerce' ) ); + } + } + + /* + |-------------------------------------------------------------------------- + | Other Actions + |-------------------------------------------------------------------------- + */ + + /** + * Returns false if the product cannot be bought. + * + * @access public + * @return bool + */ + public function is_purchasable() { + return apply_filters( 'woocommerce_is_purchasable', false, $this ); + } + + /** + * Get the add to url used mainly in loops. + * + * @access public + * @return string + */ + public function add_to_cart_url() { + return apply_filters( 'woocommerce_product_add_to_cart_url', $this->get_product_url(), $this ); + } + + /** + * Get the add to cart button text for the single page. + * + * @access public + * @return string + */ + public function single_add_to_cart_text() { + return apply_filters( 'woocommerce_product_single_add_to_cart_text', $this->get_button_text() ? $this->get_button_text() : _x( 'Buy product', 'placeholder', 'woocommerce' ), $this ); + } + + /** + * Get the add to cart button text. + * + * @access public + * @return string + */ + public function add_to_cart_text() { + return apply_filters( 'woocommerce_product_add_to_cart_text', $this->get_button_text() ? $this->get_button_text() : _x( 'Buy product', 'placeholder', 'woocommerce' ), $this ); + } + + /** + * Get the add to cart button text description - used in aria tags. + * + * @since 3.3.0 + * @return string + */ + public function add_to_cart_description() { + /* translators: %s: Product title */ + return apply_filters( 'woocommerce_product_add_to_cart_description', $this->get_button_text() ? $this->get_button_text() : sprintf( __( 'Buy “%s”', 'woocommerce' ), $this->get_name() ), $this ); + } +} diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-factory.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-factory.php new file mode 100644 index 0000000..9344f67 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-factory.php @@ -0,0 +1,119 @@ +get_product_id( $product_id ); + + if ( ! $product_id ) { + return false; + } + + $product_type = $this->get_product_type( $product_id ); + + // Backwards compatibility. + if ( ! empty( $deprecated ) ) { + wc_deprecated_argument( 'args', '3.0', 'Passing args to the product factory is deprecated. If you need to force a type, construct the product class directly.' ); + + if ( isset( $deprecated['product_type'] ) ) { + $product_type = $this->get_classname_from_product_type( $deprecated['product_type'] ); + } + } + + $classname = $this->get_product_classname( $product_id, $product_type ); + + try { + return new $classname( $product_id, $deprecated ); + } catch ( Exception $e ) { + return false; + } + } + + /** + * Gets a product classname and allows filtering. Returns WC_Product_Simple if the class does not exist. + * + * @since 3.0.0 + * @param int $product_id Product ID. + * @param string $product_type Product type. + * @return string + */ + public static function get_product_classname( $product_id, $product_type ) { + $classname = apply_filters( 'woocommerce_product_class', self::get_classname_from_product_type( $product_type ), $product_type, 'variation' === $product_type ? 'product_variation' : 'product', $product_id ); + + if ( ! $classname || ! class_exists( $classname ) ) { + $classname = 'WC_Product_Simple'; + } + + return $classname; + } + + /** + * Get the product type for a product. + * + * @since 3.0.0 + * @param int $product_id Product ID. + * @return string|false + */ + public static function get_product_type( $product_id ) { + // Allow the overriding of the lookup in this function. Return the product type here. + $override = apply_filters( 'woocommerce_product_type_query', false, $product_id ); + if ( ! $override ) { + return WC_Data_Store::load( 'product' )->get_product_type( $product_id ); + } else { + return $override; + } + } + + /** + * Create a WC coding standards compliant class name e.g. WC_Product_Type_Class instead of WC_Product_type-class. + * + * @param string $product_type Product type. + * @return string|false + */ + public static function get_classname_from_product_type( $product_type ) { + return $product_type ? 'WC_Product_' . implode( '_', array_map( 'ucfirst', explode( '-', $product_type ) ) ) : false; + } + + /** + * Get the product ID depending on what was passed. + * + * @since 3.0.0 + * @param WC_Product|WP_Post|int|bool $product Product instance, post instance, numeric or false to use global $post. + * @return int|bool false on failure + */ + private function get_product_id( $product ) { + global $post; + + if ( false === $product && isset( $post, $post->ID ) && 'product' === get_post_type( $post->ID ) ) { + return absint( $post->ID ); + } elseif ( is_numeric( $product ) ) { + return $product; + } elseif ( $product instanceof WC_Product ) { + return $product->get_id(); + } elseif ( ! empty( $product->ID ) ) { + return $product->ID; + } else { + return false; + } + } +} diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-grouped.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-grouped.php new file mode 100644 index 0000000..e2b19d0 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-grouped.php @@ -0,0 +1,193 @@ + array(), + ); + + /** + * Get internal type. + * + * @return string + */ + public function get_type() { + return 'grouped'; + } + + /** + * Get the add to cart button text. + * + * @return string + */ + public function add_to_cart_text() { + return apply_filters( 'woocommerce_product_add_to_cart_text', __( 'View products', 'woocommerce' ), $this ); + } + + /** + * Get the add to cart button text description - used in aria tags. + * + * @since 3.3.0 + * @return string + */ + public function add_to_cart_description() { + /* translators: %s: Product title */ + return apply_filters( 'woocommerce_product_add_to_cart_description', sprintf( __( 'View products in the “%s” group', 'woocommerce' ), $this->get_name() ), $this ); + } + + /** + * Returns whether or not the product is on sale. + * + * @param string $context What the value is for. Valid values are view and edit. + * @return bool + */ + public function is_on_sale( $context = 'view' ) { + $children = array_filter( array_map( 'wc_get_product', $this->get_children( $context ) ), 'wc_products_array_filter_visible_grouped' ); + $on_sale = false; + + foreach ( $children as $child ) { + if ( $child->is_purchasable() && ! $child->has_child() && $child->is_on_sale() ) { + $on_sale = true; + break; + } + } + + return 'view' === $context ? apply_filters( 'woocommerce_product_is_on_sale', $on_sale, $this ) : $on_sale; + } + + /** + * Returns false if the product cannot be bought. + * + * @return bool + */ + public function is_purchasable() { + return apply_filters( 'woocommerce_is_purchasable', false, $this ); + } + + /** + * Returns the price in html format. + * + * @param string $price (default: ''). + * @return string + */ + public function get_price_html( $price = '' ) { + $tax_display_mode = get_option( 'woocommerce_tax_display_shop' ); + $child_prices = array(); + $children = array_filter( array_map( 'wc_get_product', $this->get_children() ), 'wc_products_array_filter_visible_grouped' ); + + foreach ( $children as $child ) { + if ( '' !== $child->get_price() ) { + $child_prices[] = 'incl' === $tax_display_mode ? wc_get_price_including_tax( $child ) : wc_get_price_excluding_tax( $child ); + } + } + + if ( ! empty( $child_prices ) ) { + $min_price = min( $child_prices ); + $max_price = max( $child_prices ); + } else { + $min_price = ''; + $max_price = ''; + } + + if ( '' !== $min_price ) { + if ( $min_price !== $max_price ) { + $price = wc_format_price_range( $min_price, $max_price ); + } else { + $price = wc_price( $min_price ); + } + + $is_free = 0 === $min_price && 0 === $max_price; + + if ( $is_free ) { + $price = apply_filters( 'woocommerce_grouped_free_price_html', __( 'Free!', 'woocommerce' ), $this ); + } else { + $price = apply_filters( 'woocommerce_grouped_price_html', $price . $this->get_price_suffix(), $this, $child_prices ); + } + } else { + $price = apply_filters( 'woocommerce_grouped_empty_price_html', '', $this ); + } + + return apply_filters( 'woocommerce_get_price_html', $price, $this ); + } + + /* + |-------------------------------------------------------------------------- + | Getters + |-------------------------------------------------------------------------- + | + | Methods for getting data from the product object. + */ + + /** + * Return the children of this product. + * + * @param string $context What the value is for. Valid values are view and edit. + * @return array + */ + public function get_children( $context = 'view' ) { + return $this->get_prop( 'children', $context ); + } + + /* + |-------------------------------------------------------------------------- + | Setters + |-------------------------------------------------------------------------- + | + | Methods for getting data from the product object. + */ + + /** + * Return the children of this product. + * + * @param array $children List of product children. + */ + public function set_children( $children ) { + $this->set_prop( 'children', array_filter( wp_parse_id_list( (array) $children ) ) ); + } + + /* + |-------------------------------------------------------------------------- + | Sync with children. + |-------------------------------------------------------------------------- + */ + + /** + * Sync a grouped product with it's children. These sync functions sync + * upwards (from child to parent) when the variation is saved. + * + * @param WC_Product|int $product Product object or ID for which you wish to sync. + * @param bool $save If true, the product object will be saved to the DB before returning it. + * @return WC_Product Synced product object. + */ + public static function sync( $product, $save = true ) { + if ( ! is_a( $product, 'WC_Product' ) ) { + $product = wc_get_product( $product ); + } + if ( is_a( $product, 'WC_Product_Grouped' ) ) { + $data_store = WC_Data_Store::load( 'product-' . $product->get_type() ); + $data_store->sync_price( $product ); + if ( $save ) { + $product->save(); + } + } + return $product; + } +} diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-query.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-query.php new file mode 100644 index 0000000..8562a1f --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-query.php @@ -0,0 +1,79 @@ + array( 'draft', 'pending', 'private', 'publish' ), + 'type' => array_merge( array_keys( wc_get_product_types() ) ), + 'limit' => get_option( 'posts_per_page' ), + 'include' => array(), + 'date_created' => '', + 'date_modified' => '', + 'featured' => '', + 'visibility' => '', + 'sku' => '', + 'price' => '', + 'regular_price' => '', + 'sale_price' => '', + 'date_on_sale_from' => '', + 'date_on_sale_to' => '', + 'total_sales' => '', + 'tax_status' => '', + 'tax_class' => '', + 'manage_stock' => '', + 'stock_quantity' => '', + 'stock_status' => '', + 'backorders' => '', + 'low_stock_amount' => '', + 'sold_individually' => '', + 'weight' => '', + 'length' => '', + 'width' => '', + 'height' => '', + 'reviews_allowed' => '', + 'virtual' => '', + 'downloadable' => '', + 'category' => array(), + 'tag' => array(), + 'shipping_class' => array(), + 'download_limit' => '', + 'download_expiry' => '', + 'average_rating' => '', + 'review_count' => '', + ) + ); + } + + /** + * Get products matching the current query vars. + * + * @return array|object of WC_Product objects + */ + public function get_products() { + $args = apply_filters( 'woocommerce_product_object_query_args', $this->get_query_vars() ); + $results = WC_Data_Store::load( 'product' )->query( $args ); + return apply_filters( 'woocommerce_product_object_query', $results, $args ); + } +} diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-simple.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-simple.php new file mode 100644 index 0000000..6dfebfc --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-simple.php @@ -0,0 +1,77 @@ +supports[] = 'ajax_add_to_cart'; + parent::__construct( $product ); + } + + /** + * Get internal type. + * + * @return string + */ + public function get_type() { + return 'simple'; + } + + /** + * Get the add to url used mainly in loops. + * + * @return string + */ + public function add_to_cart_url() { + $url = $this->is_purchasable() && $this->is_in_stock() ? remove_query_arg( + 'added-to-cart', + add_query_arg( + array( + 'add-to-cart' => $this->get_id(), + ), + ( function_exists( 'is_feed' ) && is_feed() ) || ( function_exists( 'is_404' ) && is_404() ) ? $this->get_permalink() : '' + ) + ) : $this->get_permalink(); + return apply_filters( 'woocommerce_product_add_to_cart_url', $url, $this ); + } + + /** + * Get the add to cart button text. + * + * @return string + */ + public function add_to_cart_text() { + $text = $this->is_purchasable() && $this->is_in_stock() ? __( 'Add to cart', 'woocommerce' ) : __( 'Read more', 'woocommerce' ); + + return apply_filters( 'woocommerce_product_add_to_cart_text', $text, $this ); + } + + /** + * Get the add to cart button text description - used in aria tags. + * + * @since 3.3.0 + * @return string + */ + public function add_to_cart_description() { + /* translators: %s: Product title */ + $text = $this->is_purchasable() && $this->is_in_stock() ? __( 'Add “%s” to your cart', 'woocommerce' ) : __( 'Read more about “%s”', 'woocommerce' ); + + return apply_filters( 'woocommerce_product_add_to_cart_description', sprintf( $text, $this->get_name() ), $this ); + } +} diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-variable.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-variable.php new file mode 100644 index 0000000..78900dd --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-variable.php @@ -0,0 +1,675 @@ +is_purchasable() ? __( 'Select options', 'woocommerce' ) : __( 'Read more', 'woocommerce' ), $this ); + } + + /** + * Get the add to cart button text description - used in aria tags. + * + * @since 3.3.0 + * @return string + */ + public function add_to_cart_description() { + /* translators: %s: Product title */ + return apply_filters( 'woocommerce_product_add_to_cart_description', sprintf( __( 'Select options for “%s”', 'woocommerce' ), $this->get_name() ), $this ); + } + + /** + * Get an array of all sale and regular prices from all variations. This is used for example when displaying the price range at variable product level or seeing if the variable product is on sale. + * + * @param bool $for_display If true, prices will be adapted for display based on the `woocommerce_tax_display_shop` setting (including or excluding taxes). + * @return array Array of RAW prices, regular prices, and sale prices with keys set to variation ID. + */ + public function get_variation_prices( $for_display = false ) { + $prices = $this->data_store->read_price_data( $this, $for_display ); + + foreach ( $prices as $price_key => $variation_prices ) { + $prices[ $price_key ] = $this->sort_variation_prices( $variation_prices ); + } + + return $prices; + } + + /** + * Get the min or max variation regular price. + * + * @param string $min_or_max Min or max price. + * @param boolean $for_display If true, prices will be adapted for display based on the `woocommerce_tax_display_shop` setting (including or excluding taxes). + * @return string + */ + public function get_variation_regular_price( $min_or_max = 'min', $for_display = false ) { + $prices = $this->get_variation_prices( $for_display ); + $price = 'min' === $min_or_max ? current( $prices['regular_price'] ) : end( $prices['regular_price'] ); + + return apply_filters( 'woocommerce_get_variation_regular_price', $price, $this, $min_or_max, $for_display ); + } + + /** + * Get the min or max variation sale price. + * + * @param string $min_or_max Min or max price. + * @param boolean $for_display If true, prices will be adapted for display based on the `woocommerce_tax_display_shop` setting (including or excluding taxes). + * @return string + */ + public function get_variation_sale_price( $min_or_max = 'min', $for_display = false ) { + $prices = $this->get_variation_prices( $for_display ); + $price = 'min' === $min_or_max ? current( $prices['sale_price'] ) : end( $prices['sale_price'] ); + + return apply_filters( 'woocommerce_get_variation_sale_price', $price, $this, $min_or_max, $for_display ); + } + + /** + * Get the min or max variation (active) price. + * + * @param string $min_or_max Min or max price. + * @param boolean $for_display If true, prices will be adapted for display based on the `woocommerce_tax_display_shop` setting (including or excluding taxes). + * @return string + */ + public function get_variation_price( $min_or_max = 'min', $for_display = false ) { + $prices = $this->get_variation_prices( $for_display ); + $price = 'min' === $min_or_max ? current( $prices['price'] ) : end( $prices['price'] ); + + return apply_filters( 'woocommerce_get_variation_price', $price, $this, $min_or_max, $for_display ); + } + + /** + * Returns the price in html format. + * + * Note: Variable prices do not show suffixes like other product types. This + * is due to some things like tax classes being set at variation level which + * could differ from the parent price. The only way to show accurate prices + * would be to load the variation and get it's price, which adds extra + * overhead and still has edge cases where the values would be inaccurate. + * + * Additionally, ranges of prices no longer show 'striked out' sale prices + * due to the strings being very long and unclear/confusing. A single range + * is shown instead. + * + * @param string $price Price (default: ''). + * @return string + */ + public function get_price_html( $price = '' ) { + $prices = $this->get_variation_prices( true ); + + if ( empty( $prices['price'] ) ) { + $price = apply_filters( 'woocommerce_variable_empty_price_html', '', $this ); + } else { + $min_price = current( $prices['price'] ); + $max_price = end( $prices['price'] ); + $min_reg_price = current( $prices['regular_price'] ); + $max_reg_price = end( $prices['regular_price'] ); + + if ( $min_price !== $max_price ) { + $price = wc_format_price_range( $min_price, $max_price ); + } elseif ( $this->is_on_sale() && $min_reg_price === $max_reg_price ) { + $price = wc_format_sale_price( wc_price( $max_reg_price ), wc_price( $min_price ) ); + } else { + $price = wc_price( $min_price ); + } + + $price = apply_filters( 'woocommerce_variable_price_html', $price . $this->get_price_suffix(), $this ); + } + + return apply_filters( 'woocommerce_get_price_html', $price, $this ); + } + + /** + * Get the suffix to display after prices > 0. + * + * This is skipped if the suffix + * has dynamic values such as {price_excluding_tax} for variable products. + * + * @see get_price_html for an explanation as to why. + * @param string $price Price to calculate, left blank to just use get_price(). + * @param integer $qty Quantity passed on to get_price_including_tax() or get_price_excluding_tax(). + * @return string + */ + public function get_price_suffix( $price = '', $qty = 1 ) { + $suffix = get_option( 'woocommerce_price_display_suffix' ); + + if ( strstr( $suffix, '{' ) ) { + return apply_filters( 'woocommerce_get_price_suffix', '', $this, $price, $qty ); + } else { + return parent::get_price_suffix( $price, $qty ); + } + } + + /** + * Return a products child ids. + * + * This is lazy loaded as it's not used often and does require several queries. + * + * @param bool|string $visible_only Visible only. + * @return array Children ids + */ + public function get_children( $visible_only = '' ) { + if ( is_bool( $visible_only ) ) { + wc_deprecated_argument( 'visible_only', '3.0', 'WC_Product_Variable::get_visible_children' ); + + return $visible_only ? $this->get_visible_children() : $this->get_children(); + } + + if ( null === $this->children ) { + $children = $this->data_store->read_children( $this ); + $this->set_children( $children['all'] ); + $this->set_visible_children( $children['visible'] ); + } + + return apply_filters( 'woocommerce_get_children', $this->children, $this, false ); + } + + /** + * Return a products child ids - visible only. + * + * This is lazy loaded as it's not used often and does require several queries. + * + * @since 3.0.0 + * @return array Children ids + */ + public function get_visible_children() { + if ( null === $this->visible_children ) { + $children = $this->data_store->read_children( $this ); + $this->set_children( $children['all'] ); + $this->set_visible_children( $children['visible'] ); + } + return apply_filters( 'woocommerce_get_children', $this->visible_children, $this, true ); + } + + /** + * Return an array of attributes used for variations, as well as their possible values. + * + * This is lazy loaded as it's not used often and does require several queries. + * + * @return array Attributes and their available values + */ + public function get_variation_attributes() { + if ( null === $this->variation_attributes ) { + $this->variation_attributes = $this->data_store->read_variation_attributes( $this ); + } + return $this->variation_attributes; + } + + /** + * If set, get the default attributes for a variable product. + * + * @param string $attribute_name Attribute name. + * @return string + */ + public function get_variation_default_attribute( $attribute_name ) { + $defaults = $this->get_default_attributes(); + $attribute_name = sanitize_title( $attribute_name ); + + return isset( $defaults[ $attribute_name ] ) ? $defaults[ $attribute_name ] : ''; + } + + /** + * Variable products themselves cannot be downloadable. + * + * @param string $context What the value is for. Valid values are view and edit. + * @return bool + */ + public function get_downloadable( $context = 'view' ) { + return false; + } + + /** + * Variable products themselves cannot be virtual. + * + * @param string $context What the value is for. Valid values are view and edit. + * @return bool + */ + public function get_virtual( $context = 'view' ) { + return false; + } + + /** + * Get an array of available variations for the current product. + * + * @param string $return Optional. The format to return the results in. Can be 'array' to return an array of variation data or 'objects' for the product objects. Default 'array'. + * + * @return array[]|WC_Product_Variation[] + */ + public function get_available_variations( $return = 'array' ) { + $variation_ids = $this->get_children(); + $available_variations = array(); + + if ( is_callable( '_prime_post_caches' ) ) { + _prime_post_caches( $variation_ids ); + } + + foreach ( $variation_ids as $variation_id ) { + + $variation = wc_get_product( $variation_id ); + + // Hide out of stock variations if 'Hide out of stock items from the catalog' is checked. + if ( ! $variation || ! $variation->exists() || ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) && ! $variation->is_in_stock() ) ) { + continue; + } + + // Filter 'woocommerce_hide_invisible_variations' to optionally hide invisible variations (disabled variations and variations with empty price). + if ( apply_filters( 'woocommerce_hide_invisible_variations', true, $this->get_id(), $variation ) && ! $variation->variation_is_visible() ) { + continue; + } + + if ( 'array' === $return ) { + $available_variations[] = $this->get_available_variation( $variation ); + } else { + $available_variations[] = $variation; + } + } + + if ( 'array' === $return ) { + $available_variations = array_values( array_filter( $available_variations ) ); + } + + return $available_variations; + } + + /** + * Check if a given variation is currently available. + * + * @param WC_Product_Variation $variation Variation to check. + * + * @return bool True if the variation is available, false otherwise. + */ + private function variation_is_available( WC_Product_Variation $variation ) { + // Hide out of stock variations if 'Hide out of stock items from the catalog' is checked. + if ( ! $variation || ! $variation->exists() || ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) && ! $variation->is_in_stock() ) ) { + return false; + } + + // Filter 'woocommerce_hide_invisible_variations' to optionally hide invisible variations (disabled variations and variations with empty price). + if ( apply_filters( 'woocommerce_hide_invisible_variations', true, $this->get_id(), $variation ) && ! $variation->variation_is_visible() ) { + return false; + } + + return true; + } + + /** + * Returns an array of data for a variation. Used in the add to cart form. + * + * @since 2.4.0 + * @param WC_Product $variation Variation product object or ID. + * @return array|bool + */ + public function get_available_variation( $variation ) { + if ( is_numeric( $variation ) ) { + $variation = wc_get_product( $variation ); + } + if ( ! $variation instanceof WC_Product_Variation ) { + return false; + } + // See if prices should be shown for each variation after selection. + $show_variation_price = apply_filters( 'woocommerce_show_variation_price', $variation->get_price() === '' || $this->get_variation_sale_price( 'min' ) !== $this->get_variation_sale_price( 'max' ) || $this->get_variation_regular_price( 'min' ) !== $this->get_variation_regular_price( 'max' ), $this, $variation ); + + return apply_filters( + 'woocommerce_available_variation', + array( + 'attributes' => $variation->get_variation_attributes(), + 'availability_html' => wc_get_stock_html( $variation ), + 'backorders_allowed' => $variation->backorders_allowed(), + 'dimensions' => $variation->get_dimensions( false ), + 'dimensions_html' => wc_format_dimensions( $variation->get_dimensions( false ) ), + 'display_price' => wc_get_price_to_display( $variation ), + 'display_regular_price' => wc_get_price_to_display( $variation, array( 'price' => $variation->get_regular_price() ) ), + 'image' => wc_get_product_attachment_props( $variation->get_image_id() ), + 'image_id' => $variation->get_image_id(), + 'is_downloadable' => $variation->is_downloadable(), + 'is_in_stock' => $variation->is_in_stock(), + 'is_purchasable' => $variation->is_purchasable(), + 'is_sold_individually' => $variation->is_sold_individually() ? 'yes' : 'no', + 'is_virtual' => $variation->is_virtual(), + 'max_qty' => 0 < $variation->get_max_purchase_quantity() ? $variation->get_max_purchase_quantity() : '', + 'min_qty' => $variation->get_min_purchase_quantity(), + 'price_html' => $show_variation_price ? '' . $variation->get_price_html() . '' : '', + 'sku' => $variation->get_sku(), + 'variation_description' => wc_format_content( $variation->get_description() ), + 'variation_id' => $variation->get_id(), + 'variation_is_active' => $variation->variation_is_active(), + 'variation_is_visible' => $variation->variation_is_visible(), + 'weight' => $variation->get_weight(), + 'weight_html' => wc_format_weight( $variation->get_weight() ), + ), + $this, + $variation + ); + } + + /* + |-------------------------------------------------------------------------- + | Setters + |-------------------------------------------------------------------------- + */ + + /** + * Sets an array of variation attributes. + * + * @since 3.0.0 + * @param array $variation_attributes Attributes list. + */ + public function set_variation_attributes( $variation_attributes ) { + $this->variation_attributes = $variation_attributes; + } + + /** + * Sets an array of children for the product. + * + * @since 3.0.0 + * @param array $children Children products. + */ + public function set_children( $children ) { + $this->children = array_filter( wp_parse_id_list( (array) $children ) ); + } + + /** + * Sets an array of visible children only. + * + * @since 3.0.0 + * @param array $visible_children List of visible children products. + */ + public function set_visible_children( $visible_children ) { + $this->visible_children = array_filter( wp_parse_id_list( (array) $visible_children ) ); + } + + /* + |-------------------------------------------------------------------------- + | CRUD methods + |-------------------------------------------------------------------------- + */ + + /** + * Ensure properties are set correctly before save. + * + * @since 3.0.0 + */ + public function validate_props() { + parent::validate_props(); + + if ( ! $this->get_manage_stock() ) { + $this->data_store->sync_stock_status( $this ); + } + } + + /** + * Save data (either create or update depending on if we are working on an existing product). + * + * @since 3.0.0 + */ + public function save() { + $this->validate_props(); + + if ( ! $this->data_store ) { + return $this->get_id(); + } + + /** + * Trigger action before saving to the DB. Allows you to adjust object props before save. + * + * @param WC_Data $this The object being saved. + * @param WC_Data_Store_WP $data_store The data store persisting the data. + */ + do_action( 'woocommerce_before_' . $this->object_type . '_object_save', $this, $this->data_store ); + + // Get names before save. + $previous_name = $this->data['name']; + $new_name = $this->get_name( 'edit' ); + + if ( $this->get_id() ) { + $this->data_store->update( $this ); + } else { + $this->data_store->create( $this ); + } + + $this->data_store->sync_variation_names( $this, $previous_name, $new_name ); + $this->data_store->sync_managed_variation_stock_status( $this ); + + /** + * Trigger action after saving to the DB. + * + * @param WC_Data $this The object being saved. + * @param WC_Data_Store_WP $data_store The data store persisting the data. + */ + do_action( 'woocommerce_after_' . $this->object_type . '_object_save', $this, $this->data_store ); + + return $this->get_id(); + } + + /* + |-------------------------------------------------------------------------- + | Conditionals + |-------------------------------------------------------------------------- + */ + + /** + * Returns whether or not the product is on sale. + * + * @param string $context What the value is for. Valid values are view and edit. What the value is for. Valid values are view and edit. + * @return bool + */ + public function is_on_sale( $context = 'view' ) { + $prices = $this->get_variation_prices(); + $on_sale = $prices['regular_price'] !== $prices['sale_price'] && $prices['sale_price'] === $prices['price']; + + return 'view' === $context ? apply_filters( 'woocommerce_product_is_on_sale', $on_sale, $this ) : $on_sale; + } + + /** + * Is a child in stock? + * + * @return boolean + */ + public function child_is_in_stock() { + return $this->data_store->child_is_in_stock( $this ); + } + + /** + * Is a child on backorder? + * + * @since 3.3.0 + * @return boolean + */ + public function child_is_on_backorder() { + return $this->data_store->child_has_stock_status( $this, 'onbackorder' ); + } + + /** + * Does a child have a weight set? + * + * @return boolean + */ + public function child_has_weight() { + $transient_name = 'wc_child_has_weight_' . $this->get_id(); + $has_weight = get_transient( $transient_name ); + + if ( false === $has_weight ) { + $has_weight = $this->data_store->child_has_weight( $this ); + set_transient( $transient_name, (int) $has_weight, DAY_IN_SECONDS * 30 ); + } + + return (bool) $has_weight; + } + + /** + * Does a child have dimensions set? + * + * @return boolean + */ + public function child_has_dimensions() { + $transient_name = 'wc_child_has_dimensions_' . $this->get_id(); + $has_dimension = get_transient( $transient_name ); + + if ( false === $has_dimension ) { + $has_dimension = $this->data_store->child_has_dimensions( $this ); + set_transient( $transient_name, (int) $has_dimension, DAY_IN_SECONDS * 30 ); + } + + return (bool) $has_dimension; + } + + /** + * Returns whether or not the product has dimensions set. + * + * @return bool + */ + public function has_dimensions() { + return parent::has_dimensions() || $this->child_has_dimensions(); + } + + /** + * Returns whether or not the product has weight set. + * + * @return bool + */ + public function has_weight() { + return parent::has_weight() || $this->child_has_weight(); + } + + /** + * Returns whether or not the product has additional options that need + * selecting before adding to cart. + * + * @since 3.0.0 + * @return boolean + */ + public function has_options() { + return apply_filters( 'woocommerce_product_has_options', true, $this ); + } + + + /* + |-------------------------------------------------------------------------- + | Sync with child variations. + |-------------------------------------------------------------------------- + */ + + /** + * Sync a variable product with it's children. These sync functions sync + * upwards (from child to parent) when the variation is saved. + * + * @param WC_Product|int $product Product object or ID for which you wish to sync. + * @param bool $save If true, the product object will be saved to the DB before returning it. + * @return WC_Product Synced product object. + */ + public static function sync( $product, $save = true ) { + if ( ! is_a( $product, 'WC_Product' ) ) { + $product = wc_get_product( $product ); + } + if ( is_a( $product, 'WC_Product_Variable' ) ) { + $data_store = WC_Data_Store::load( 'product-' . $product->get_type() ); + $data_store->sync_price( $product ); + $data_store->sync_stock_status( $product ); + self::sync_attributes( $product ); // Legacy update of attributes. + + do_action( 'woocommerce_variable_product_sync_data', $product ); + + if ( $save ) { + $product->save(); + } + + wc_do_deprecated_action( + 'woocommerce_variable_product_sync', + array( + $product->get_id(), + $product->get_visible_children(), + ), + '3.0', + 'woocommerce_variable_product_sync_data, woocommerce_new_product or woocommerce_update_product' + ); + } + + return $product; + } + + /** + * Sync parent stock status with the status of all children and save. + * + * @param WC_Product|int $product Product object or ID for which you wish to sync. + * @param bool $save If true, the product object will be saved to the DB before returning it. + * @return WC_Product Synced product object. + */ + public static function sync_stock_status( $product, $save = true ) { + if ( ! is_a( $product, 'WC_Product' ) ) { + $product = wc_get_product( $product ); + } + if ( is_a( $product, 'WC_Product_Variable' ) ) { + $data_store = WC_Data_Store::load( 'product-' . $product->get_type() ); + $data_store->sync_stock_status( $product ); + + if ( $save ) { + $product->save(); + } + } + + return $product; + } + + /** + * Sort an associative array of $variation_id => $price pairs in order of min and max prices. + * + * @param array $prices associative array of $variation_id => $price pairs. + * @return array + */ + protected function sort_variation_prices( $prices ) { + asort( $prices ); + + return $prices; + } +} diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-variation.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-variation.php new file mode 100644 index 0000000..ebd2838 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-variation.php @@ -0,0 +1,603 @@ + '', + 'sku' => '', + 'manage_stock' => '', + 'backorders' => '', + 'stock_quantity' => '', + 'weight' => '', + 'length' => '', + 'width' => '', + 'height' => '', + 'tax_class' => '', + 'shipping_class_id' => '', + 'image_id' => '', + 'purchase_note' => '', + ); + + /** + * Override the default constructor to set custom defaults. + * + * @param int|WC_Product|object $product Product to init. + */ + public function __construct( $product = 0 ) { + $this->data['tax_class'] = 'parent'; + $this->data['attribute_summary'] = ''; + parent::__construct( $product ); + } + + /** + * Prefix for action and filter hooks on data. + * + * @since 3.0.0 + * @return string + */ + protected function get_hook_prefix() { + return 'woocommerce_product_variation_get_'; + } + + /** + * Get internal type. + * + * @return string + */ + public function get_type() { + return 'variation'; + } + + /** + * If the stock level comes from another product ID. + * + * @since 3.0.0 + * @return int + */ + public function get_stock_managed_by_id() { + return 'parent' === $this->get_manage_stock() ? $this->get_parent_id() : $this->get_id(); + } + + /** + * Get the product's title. For variations this is the parent product name. + * + * @return string + */ + public function get_title() { + return apply_filters( 'woocommerce_product_title', $this->parent_data['title'], $this ); + } + + /** + * Get product name with SKU or ID. Used within admin. + * + * @return string Formatted product name + */ + public function get_formatted_name() { + if ( $this->get_sku() ) { + $identifier = $this->get_sku(); + } else { + $identifier = '#' . $this->get_id(); + } + + $formatted_variation_list = wc_get_formatted_variation( $this, true, true, true ); + + return sprintf( '%2$s (%1$s)', $identifier, $this->get_name() ) . '' . $formatted_variation_list . ''; + } + + /** + * Get variation attribute values. Keys are prefixed with attribute_, as stored, unless $with_prefix is false. + * + * @param bool $with_prefix Whether keys should be prepended with attribute_ or not, default is true. + * @return array of attributes and their values for this variation. + */ + public function get_variation_attributes( $with_prefix = true ) { + $attributes = $this->get_attributes(); + $variation_attributes = array(); + $prefix = $with_prefix ? 'attribute_' : ''; + + foreach ( $attributes as $key => $value ) { + $variation_attributes[ $prefix . $key ] = $value; + } + return $variation_attributes; + } + + /** + * Returns a single product attribute as a string. + * + * @param string $attribute to get. + * @return string + */ + public function get_attribute( $attribute ) { + $attributes = $this->get_attributes(); + $attribute = sanitize_title( $attribute ); + + if ( isset( $attributes[ $attribute ] ) ) { + $value = $attributes[ $attribute ]; + $term = taxonomy_exists( $attribute ) ? get_term_by( 'slug', $value, $attribute ) : false; + return ! is_wp_error( $term ) && $term ? $term->name : $value; + } + + $att_str = 'pa_' . $attribute; + if ( isset( $attributes[ $att_str ] ) ) { + $value = $attributes[ $att_str ]; + $term = taxonomy_exists( $att_str ) ? get_term_by( 'slug', $value, $att_str ) : false; + return ! is_wp_error( $term ) && $term ? $term->name : $value; + } + + return ''; + } + + /** + * Wrapper for get_permalink. Adds this variations attributes to the URL. + * + * @param array|null $item_object item array If a cart or order item is passed, we can get a link containing the exact attributes selected for the variation, rather than the default attributes. + * @return string + */ + public function get_permalink( $item_object = null ) { + $url = get_permalink( $this->get_parent_id() ); + + if ( ! empty( $item_object['variation'] ) ) { + $data = $item_object['variation']; + } elseif ( ! empty( $item_object['item_meta_array'] ) ) { + $data_keys = array_map( 'wc_variation_attribute_name', wp_list_pluck( $item_object['item_meta_array'], 'key' ) ); + $data_values = wp_list_pluck( $item_object['item_meta_array'], 'value' ); + $data = array_intersect_key( array_combine( $data_keys, $data_values ), $this->get_variation_attributes() ); + } else { + $data = $this->get_variation_attributes(); + } + + $data = array_filter( $data, 'wc_array_filter_default_attributes' ); + + if ( empty( $data ) ) { + return $url; + } + + // Filter and encode keys and values so this is not broken by add_query_arg. + $data = array_map( 'urlencode', $data ); + $keys = array_map( 'urlencode', array_keys( $data ) ); + + return add_query_arg( array_combine( $keys, $data ), $url ); + } + + /** + * Get the add to url used mainly in loops. + * + * @return string + */ + public function add_to_cart_url() { + $url = $this->is_purchasable() ? remove_query_arg( + 'added-to-cart', + add_query_arg( + array( + 'variation_id' => $this->get_id(), + 'add-to-cart' => $this->get_parent_id(), + ), + $this->get_permalink() + ) + ) : $this->get_permalink(); + return apply_filters( 'woocommerce_product_add_to_cart_url', $url, $this ); + } + + /** + * Get SKU (Stock-keeping unit) - product unique ID. + * + * @param string $context What the value is for. Valid values are view and edit. + * @return string + */ + public function get_sku( $context = 'view' ) { + $value = $this->get_prop( 'sku', $context ); + + // Inherit value from parent. + if ( 'view' === $context && empty( $value ) ) { + $value = apply_filters( $this->get_hook_prefix() . 'sku', $this->parent_data['sku'], $this ); + } + return $value; + } + + /** + * Returns the product's weight. + * + * @param string $context What the value is for. Valid values are view and edit. + * @return string + */ + public function get_weight( $context = 'view' ) { + $value = $this->get_prop( 'weight', $context ); + + // Inherit value from parent. + if ( 'view' === $context && empty( $value ) ) { + $value = apply_filters( $this->get_hook_prefix() . 'weight', $this->parent_data['weight'], $this ); + } + return $value; + } + + /** + * Returns the product length. + * + * @param string $context What the value is for. Valid values are view and edit. + * @return string + */ + public function get_length( $context = 'view' ) { + $value = $this->get_prop( 'length', $context ); + + // Inherit value from parent. + if ( 'view' === $context && empty( $value ) ) { + $value = apply_filters( $this->get_hook_prefix() . 'length', $this->parent_data['length'], $this ); + } + return $value; + } + + /** + * Returns the product width. + * + * @param string $context What the value is for. Valid values are view and edit. + * @return string + */ + public function get_width( $context = 'view' ) { + $value = $this->get_prop( 'width', $context ); + + // Inherit value from parent. + if ( 'view' === $context && empty( $value ) ) { + $value = apply_filters( $this->get_hook_prefix() . 'width', $this->parent_data['width'], $this ); + } + return $value; + } + + /** + * Returns the product height. + * + * @param string $context What the value is for. Valid values are view and edit. + * @return string + */ + public function get_height( $context = 'view' ) { + $value = $this->get_prop( 'height', $context ); + + // Inherit value from parent. + if ( 'view' === $context && empty( $value ) ) { + $value = apply_filters( $this->get_hook_prefix() . 'height', $this->parent_data['height'], $this ); + } + return $value; + } + + /** + * Returns the tax class. + * + * Does not use get_prop so it can handle 'parent' inheritance correctly. + * + * @param string $context view, edit, or unfiltered. + * @return string + */ + public function get_tax_class( $context = 'view' ) { + $value = null; + + if ( array_key_exists( 'tax_class', $this->data ) ) { + $value = array_key_exists( 'tax_class', $this->changes ) ? $this->changes['tax_class'] : $this->data['tax_class']; + + if ( 'edit' !== $context && 'parent' === $value ) { + $value = $this->parent_data['tax_class']; + } + + if ( 'view' === $context ) { + $value = apply_filters( $this->get_hook_prefix() . 'tax_class', $value, $this ); + } + } + return $value; + } + + /** + * Return if product manage stock. + * + * @since 3.0.0 + * @param string $context What the value is for. Valid values are view and edit. + * @return boolean|string true, false, or parent. + */ + public function get_manage_stock( $context = 'view' ) { + $value = $this->get_prop( 'manage_stock', $context ); + + // Inherit value from parent. + if ( 'view' === $context && false === $value && true === wc_string_to_bool( $this->parent_data['manage_stock'] ) ) { + $value = 'parent'; + } + return $value; + } + + /** + * Returns number of items available for sale. + * + * @param string $context What the value is for. Valid values are view and edit. + * @return int|null + */ + public function get_stock_quantity( $context = 'view' ) { + $value = $this->get_prop( 'stock_quantity', $context ); + + // Inherit value from parent. + if ( 'view' === $context && 'parent' === $this->get_manage_stock() ) { + $value = apply_filters( $this->get_hook_prefix() . 'stock_quantity', $this->parent_data['stock_quantity'], $this ); + } + return $value; + } + + /** + * Get backorders. + * + * @param string $context What the value is for. Valid values are view and edit. + * @since 3.0.0 + * @return string yes no or notify + */ + public function get_backorders( $context = 'view' ) { + $value = $this->get_prop( 'backorders', $context ); + + // Inherit value from parent. + if ( 'view' === $context && 'parent' === $this->get_manage_stock() ) { + $value = apply_filters( $this->get_hook_prefix() . 'backorders', $this->parent_data['backorders'], $this ); + } + return $value; + } + + /** + * Get main image ID. + * + * @since 3.0.0 + * @param string $context What the value is for. Valid values are view and edit. + * @return string + */ + public function get_image_id( $context = 'view' ) { + $image_id = $this->get_prop( 'image_id', $context ); + + if ( 'view' === $context && ! $image_id ) { + $image_id = apply_filters( $this->get_hook_prefix() . 'image_id', $this->parent_data['image_id'], $this ); + } + + return $image_id; + } + + /** + * Get purchase note. + * + * @since 3.0.0 + * @param string $context What the value is for. Valid values are view and edit. + * @return string + */ + public function get_purchase_note( $context = 'view' ) { + $value = $this->get_prop( 'purchase_note', $context ); + + // Inherit value from parent. + if ( 'view' === $context && empty( $value ) ) { + $value = apply_filters( $this->get_hook_prefix() . 'purchase_note', $this->parent_data['purchase_note'], $this ); + } + return $value; + } + + /** + * Get shipping class ID. + * + * @since 3.0.0 + * @param string $context What the value is for. Valid values are view and edit. + * @return int + */ + public function get_shipping_class_id( $context = 'view' ) { + $shipping_class_id = $this->get_prop( 'shipping_class_id', $context ); + + if ( 'view' === $context && ! $shipping_class_id ) { + $shipping_class_id = apply_filters( $this->get_hook_prefix() . 'shipping_class_id', $this->parent_data['shipping_class_id'], $this ); + } + + return $shipping_class_id; + } + + /** + * Get catalog visibility. + * + * @param string $context What the value is for. Valid values are view and edit. + * @return string + */ + public function get_catalog_visibility( $context = 'view' ) { + return apply_filters( $this->get_hook_prefix() . 'catalog_visibility', $this->parent_data['catalog_visibility'], $this ); + } + + /** + * Get attribute summary. + * + * By default, attribute summary contains comma-delimited 'attribute_name: attribute_value' pairs for all attributes. + * + * @param string $context What the value is for. Valid values are view and edit. + * + * @since 3.6.0 + * @return string + */ + public function get_attribute_summary( $context = 'view' ) { + return $this->get_prop( 'attribute_summary', $context ); + } + + + /** + * Set attribute summary. + * + * By default, attribute summary contains comma-delimited 'attribute_name: attribute_value' pairs for all attributes. + * + * @since 3.6.0 + * @param string $attribute_summary Summary of attribute names and values assigned to the variation. + */ + public function set_attribute_summary( $attribute_summary ) { + $this->set_prop( 'attribute_summary', $attribute_summary ); + } + + /* + |-------------------------------------------------------------------------- + | CRUD methods + |-------------------------------------------------------------------------- + */ + + /** + * Set the parent data array for this variation. + * + * @since 3.0.0 + * @param array $parent_data parent data array for this variation. + */ + public function set_parent_data( $parent_data ) { + $parent_data = wp_parse_args( + $parent_data, + array( + 'title' => '', + 'status' => '', + 'sku' => '', + 'manage_stock' => 'no', + 'backorders' => 'no', + 'stock_quantity' => '', + 'weight' => '', + 'length' => '', + 'width' => '', + 'height' => '', + 'tax_class' => '', + 'shipping_class_id' => 0, + 'image_id' => 0, + 'purchase_note' => '', + 'catalog_visibility' => 'visible', + ) + ); + + // Normalize tax class. + $parent_data['tax_class'] = sanitize_title( $parent_data['tax_class'] ); + $parent_data['tax_class'] = 'standard' === $parent_data['tax_class'] ? '' : $parent_data['tax_class']; + $valid_classes = $this->get_valid_tax_classes(); + + if ( ! in_array( $parent_data['tax_class'], $valid_classes, true ) ) { + $parent_data['tax_class'] = ''; + } + + $this->parent_data = $parent_data; + } + + /** + * Get the parent data array for this variation. + * + * @since 3.0.0 + * @return array + */ + public function get_parent_data() { + return $this->parent_data; + } + + /** + * Set attributes. Unlike the parent product which uses terms, variations are assigned + * specific attributes using name value pairs. + * + * @param array $raw_attributes array of raw attributes. + */ + public function set_attributes( $raw_attributes ) { + $raw_attributes = (array) $raw_attributes; + $attributes = array(); + + foreach ( $raw_attributes as $key => $value ) { + // Remove attribute prefix which meta gets stored with. + if ( 0 === strpos( $key, 'attribute_' ) ) { + $key = substr( $key, 10 ); + } + $attributes[ $key ] = $value; + } + $this->set_prop( 'attributes', $attributes ); + } + + /** + * Returns whether or not the product has any visible attributes. + * + * Variations are mapped to specific attributes unlike products, and the return + * value of ->get_attributes differs. Therefore this returns false. + * + * @return boolean + */ + public function has_attributes() { + return false; + } + + /* + |-------------------------------------------------------------------------- + | Conditionals + |-------------------------------------------------------------------------- + */ + + /** + * Returns false if the product cannot be bought. + * Override abstract method so that: i) Disabled variations are not be purchasable by admins. ii) Enabled variations are not purchasable if the parent product is not purchasable. + * + * @return bool + */ + public function is_purchasable() { + return apply_filters( 'woocommerce_variation_is_purchasable', $this->variation_is_visible() && parent::is_purchasable() && ( 'publish' === $this->parent_data['status'] || current_user_can( 'edit_post', $this->get_parent_id() ) ), $this ); + } + + /** + * Controls whether this particular variation will appear greyed-out (inactive) or not (active). + * Used by extensions to make incompatible variations appear greyed-out, etc. + * Other possible uses: prevent out-of-stock variations from being selected. + * + * @return bool + */ + public function variation_is_active() { + return apply_filters( 'woocommerce_variation_is_active', true, $this ); + } + + /** + * Checks if this particular variation is visible. Invisible variations are enabled and can be selected, but no price / stock info is displayed. + * Instead, a suitable 'unavailable' message is displayed. + * Invisible by default: Disabled variations and variations with an empty price. + * + * @return bool + */ + public function variation_is_visible() { + return apply_filters( 'woocommerce_variation_is_visible', 'publish' === get_post_status( $this->get_id() ) && '' !== $this->get_price(), $this->get_id(), $this->get_parent_id(), $this ); + } + + /** + * Return valid tax classes. Adds 'parent' to the default list of valid tax classes. + * + * @return array valid tax classes + */ + protected function get_valid_tax_classes() { + $valid_classes = WC_Tax::get_tax_class_slugs(); + $valid_classes[] = 'parent'; + + return $valid_classes; + } + + /** + * Delete variation, set the ID to 0, and return result. + * + * @since 4.4.0 + * @param bool $force_delete Should the variation be deleted permanently. + * @return bool result + */ + public function delete( $force_delete = false ) { + $variation_id = $this->get_id(); + + if ( ! parent::delete( $force_delete ) ) { + return false; + } + + return true; + } +} diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-query.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-query.php new file mode 100644 index 0000000..1f2e331 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-query.php @@ -0,0 +1,971 @@ +init_query_vars(); + } + + /** + * Get any errors from querystring. + */ + public function get_errors() { + // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $error = ! empty( $_GET['wc_error'] ) ? sanitize_text_field( wp_unslash( $_GET['wc_error'] ) ) : ''; + + if ( $error && ! wc_has_notice( $error, 'error' ) ) { + wc_add_notice( $error, 'error' ); + } + } + + /** + * Init query vars by loading options. + */ + public function init_query_vars() { + // Query vars to add to WP. + $this->query_vars = array( + // Checkout actions. + 'order-pay' => get_option( 'woocommerce_checkout_pay_endpoint', 'order-pay' ), + 'order-received' => get_option( 'woocommerce_checkout_order_received_endpoint', 'order-received' ), + // My account actions. + 'orders' => get_option( 'woocommerce_myaccount_orders_endpoint', 'orders' ), + 'view-order' => get_option( 'woocommerce_myaccount_view_order_endpoint', 'view-order' ), + 'downloads' => get_option( 'woocommerce_myaccount_downloads_endpoint', 'downloads' ), + 'edit-account' => get_option( 'woocommerce_myaccount_edit_account_endpoint', 'edit-account' ), + 'edit-address' => get_option( 'woocommerce_myaccount_edit_address_endpoint', 'edit-address' ), + 'payment-methods' => get_option( 'woocommerce_myaccount_payment_methods_endpoint', 'payment-methods' ), + 'lost-password' => get_option( 'woocommerce_myaccount_lost_password_endpoint', 'lost-password' ), + 'customer-logout' => get_option( 'woocommerce_logout_endpoint', 'customer-logout' ), + 'add-payment-method' => get_option( 'woocommerce_myaccount_add_payment_method_endpoint', 'add-payment-method' ), + 'delete-payment-method' => get_option( 'woocommerce_myaccount_delete_payment_method_endpoint', 'delete-payment-method' ), + 'set-default-payment-method' => get_option( 'woocommerce_myaccount_set_default_payment_method_endpoint', 'set-default-payment-method' ), + ); + } + + /** + * Get page title for an endpoint. + * + * @param string $endpoint Endpoint key. + * @param string $action Optional action or variation within the endpoint. + * + * @since 2.3.0 + * @since 4.6.0 Added $action parameter. + * @return string The page title. + */ + public function get_endpoint_title( $endpoint, $action = '' ) { + global $wp; + + switch ( $endpoint ) { + case 'order-pay': + $title = __( 'Pay for order', 'woocommerce' ); + break; + case 'order-received': + $title = __( 'Order received', 'woocommerce' ); + break; + case 'orders': + if ( ! empty( $wp->query_vars['orders'] ) ) { + /* translators: %s: page */ + $title = sprintf( __( 'Orders (page %d)', 'woocommerce' ), intval( $wp->query_vars['orders'] ) ); + } else { + $title = __( 'Orders', 'woocommerce' ); + } + break; + case 'view-order': + $order = wc_get_order( $wp->query_vars['view-order'] ); + /* translators: %s: order number */ + $title = ( $order ) ? sprintf( __( 'Order #%s', 'woocommerce' ), $order->get_order_number() ) : ''; + break; + case 'downloads': + $title = __( 'Downloads', 'woocommerce' ); + break; + case 'edit-account': + $title = __( 'Account details', 'woocommerce' ); + break; + case 'edit-address': + $title = __( 'Addresses', 'woocommerce' ); + break; + case 'payment-methods': + $title = __( 'Payment methods', 'woocommerce' ); + break; + case 'add-payment-method': + $title = __( 'Add payment method', 'woocommerce' ); + break; + case 'lost-password': + if ( in_array( $action, array( 'rp', 'resetpass', 'newaccount' ) ) ) { + $title = __( 'Set password', 'woocommerce' ); + } else { + $title = __( 'Lost password', 'woocommerce' ); + } + break; + default: + $title = ''; + break; + } + + /** + * Filters the page title used for my-account endpoints. + * + * @since 2.6.0 + * @since 4.6.0 Added $action parameter. + * + * @see get_endpoint_title() + * + * @param string $title Default title. + * @param string $endpoint Endpoint key. + * @param string $action Optional action or variation within the endpoint. + */ + return apply_filters( 'woocommerce_endpoint_' . $endpoint . '_title', $title, $endpoint, $action ); + } + + /** + * Endpoint mask describing the places the endpoint should be added. + * + * @since 2.6.2 + * @return int + */ + public function get_endpoints_mask() { + if ( 'page' === get_option( 'show_on_front' ) ) { + $page_on_front = get_option( 'page_on_front' ); + $myaccount_page_id = get_option( 'woocommerce_myaccount_page_id' ); + $checkout_page_id = get_option( 'woocommerce_checkout_page_id' ); + + if ( in_array( $page_on_front, array( $myaccount_page_id, $checkout_page_id ), true ) ) { + return EP_ROOT | EP_PAGES; + } + } + + return EP_PAGES; + } + + /** + * Add endpoints for query vars. + */ + public function add_endpoints() { + $mask = $this->get_endpoints_mask(); + + foreach ( $this->get_query_vars() as $key => $var ) { + if ( ! empty( $var ) ) { + add_rewrite_endpoint( $var, $mask ); + } + } + } + + /** + * Add query vars. + * + * @param array $vars Query vars. + * @return array + */ + public function add_query_vars( $vars ) { + foreach ( $this->get_query_vars() as $key => $var ) { + $vars[] = $key; + } + return $vars; + } + + /** + * Get query vars. + * + * @return array + */ + public function get_query_vars() { + return apply_filters( 'woocommerce_get_query_vars', $this->query_vars ); + } + + /** + * Get query current active query var. + * + * @return string + */ + public function get_current_endpoint() { + global $wp; + + foreach ( $this->get_query_vars() as $key => $value ) { + if ( isset( $wp->query_vars[ $key ] ) ) { + return $key; + } + } + return ''; + } + + /** + * Parse the request and look for query vars - endpoints may not be supported. + */ + public function parse_request() { + global $wp; + + // phpcs:disable WordPress.Security.NonceVerification.Recommended + // Map query vars to their keys, or get them if endpoints are not supported. + foreach ( $this->get_query_vars() as $key => $var ) { + if ( isset( $_GET[ $var ] ) ) { + $wp->query_vars[ $key ] = sanitize_text_field( wp_unslash( $_GET[ $var ] ) ); + } elseif ( isset( $wp->query_vars[ $var ] ) ) { + $wp->query_vars[ $key ] = $wp->query_vars[ $var ]; + } + } + // phpcs:enable WordPress.Security.NonceVerification.Recommended + } + + /** + * Are we currently on the front page? + * + * @param WP_Query $q Query instance. + * @return bool + */ + private function is_showing_page_on_front( $q ) { + return ( $q->is_home() && ! $q->is_posts_page ) && 'page' === get_option( 'show_on_front' ); + } + + /** + * Is the front page a page we define? + * + * @param int $page_id Page ID. + * @return bool + */ + private function page_on_front_is( $page_id ) { + return absint( get_option( 'page_on_front' ) ) === absint( $page_id ); + } + + /** + * Hook into pre_get_posts to do the main product query. + * + * @param WP_Query $q Query instance. + */ + public function pre_get_posts( $q ) { + // We only want to affect the main query. + if ( ! $q->is_main_query() ) { + return; + } + + // Fixes for queries on static homepages. + if ( $this->is_showing_page_on_front( $q ) ) { + + // Fix for endpoints on the homepage. + if ( ! $this->page_on_front_is( $q->get( 'page_id' ) ) ) { + $_query = wp_parse_args( $q->query ); + if ( ! empty( $_query ) && array_intersect( array_keys( $_query ), array_keys( $this->get_query_vars() ) ) ) { + $q->is_page = true; + $q->is_home = false; + $q->is_singular = true; + $q->set( 'page_id', (int) get_option( 'page_on_front' ) ); + add_filter( 'redirect_canonical', '__return_false' ); + } + } + + // When orderby is set, WordPress shows posts on the front-page. Get around that here. + if ( $this->page_on_front_is( wc_get_page_id( 'shop' ) ) ) { + $_query = wp_parse_args( $q->query ); + if ( empty( $_query ) || ! array_diff( array_keys( $_query ), array( 'preview', 'page', 'paged', 'cpage', 'orderby' ) ) ) { + $q->set( 'page_id', (int) get_option( 'page_on_front' ) ); + $q->is_page = true; + $q->is_home = false; + + // WP supporting themes show post type archive. + if ( current_theme_supports( 'woocommerce' ) ) { + $q->set( 'post_type', 'product' ); + } else { + $q->is_singular = true; + } + } + } elseif ( ! empty( $_GET['orderby'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $q->set( 'page_id', (int) get_option( 'page_on_front' ) ); + $q->is_page = true; + $q->is_home = false; + $q->is_singular = true; + } + } + + // Fix product feeds. + if ( $q->is_feed() && $q->is_post_type_archive( 'product' ) ) { + $q->is_comment_feed = false; + } + + // Special check for shops with the PRODUCT POST TYPE ARCHIVE on front. + if ( current_theme_supports( 'woocommerce' ) && $q->is_page() && 'page' === get_option( 'show_on_front' ) && absint( $q->get( 'page_id' ) ) === wc_get_page_id( 'shop' ) ) { + // This is a front-page shop. + $q->set( 'post_type', 'product' ); + $q->set( 'page_id', '' ); + + if ( isset( $q->query['paged'] ) ) { + $q->set( 'paged', $q->query['paged'] ); + } + + // Define a variable so we know this is the front page shop later on. + wc_maybe_define_constant( 'SHOP_IS_ON_FRONT', true ); + + // Get the actual WP page to avoid errors and let us use is_front_page(). + // This is hacky but works. Awaiting https://core.trac.wordpress.org/ticket/21096. + global $wp_post_types; + + $shop_page = get_post( wc_get_page_id( 'shop' ) ); + + $wp_post_types['product']->ID = $shop_page->ID; + $wp_post_types['product']->post_title = $shop_page->post_title; + $wp_post_types['product']->post_name = $shop_page->post_name; + $wp_post_types['product']->post_type = $shop_page->post_type; + $wp_post_types['product']->ancestors = get_ancestors( $shop_page->ID, $shop_page->post_type ); + + // Fix conditional Functions like is_front_page. + $q->is_singular = false; + $q->is_post_type_archive = true; + $q->is_archive = true; + $q->is_page = true; + + // Remove post type archive name from front page title tag. + add_filter( 'post_type_archive_title', '__return_empty_string', 5 ); + + // Fix WP SEO. + if ( class_exists( 'WPSEO_Meta' ) ) { + add_filter( 'wpseo_metadesc', array( $this, 'wpseo_metadesc' ) ); + add_filter( 'wpseo_metakey', array( $this, 'wpseo_metakey' ) ); + } + } elseif ( ! $q->is_post_type_archive( 'product' ) && ! $q->is_tax( get_object_taxonomies( 'product' ) ) ) { + // Only apply to product categories, the product post archive, the shop page, product tags, and product attribute taxonomies. + return; + } + + $this->product_query( $q ); + } + + /** + * Handler for the 'the_posts' WP filter. + * + * @param array $posts Posts from WP Query. + * @param WP_Query $query Current query. + * + * @return array + */ + public function handle_get_posts( $posts, $query ) { + if ( 'product_query' !== $query->get( 'wc_query' ) ) { + return $posts; + } + $this->remove_product_query_filters( $posts ); + return $posts; + } + + + /** + * Pre_get_posts above may adjust the main query to add WooCommerce logic. When this query is done, we need to ensure + * all custom filters are removed. + * + * This is done here during the_posts filter. The input is not changed. + * + * @param array $posts Posts from WP Query. + * @return array + */ + public function remove_product_query_filters( $posts ) { + $this->remove_ordering_args(); + remove_filter( 'posts_clauses', array( $this, 'price_filter_post_clauses' ), 10, 2 ); + return $posts; + } + + /** + * This function used to be hooked to found_posts and adjust the posts count when the filtering by attribute + * widget was used and variable products were present. Now it isn't hooked anymore and does nothing but return + * the input unchanged, since the pull request in which it was introduced has been reverted. + * + * @since 4.4.0 + * @param int $count Original posts count, as supplied by the found_posts filter. + * @param WP_Query $query The current WP_Query object. + * + * @return int Adjusted posts count. + */ + public function adjust_posts_count( $count, $query ) { + return $count; + } + + /** + * Instance version of get_layered_nav_chosen_attributes, needed for unit tests. + * + * @return array + */ + protected function get_layered_nav_chosen_attributes_inst() { + return self::get_layered_nav_chosen_attributes(); + } + + /** + * Get the posts (or the ids of the posts) found in the current WP loop. + * + * @return array Array of posts or post ids. + */ + protected function get_current_posts() { + return $GLOBALS['wp_query']->posts; + } + + /** + * WP SEO meta description. + * + * Hooked into wpseo_ hook already, so no need for function_exist. + * + * @return string + */ + public function wpseo_metadesc() { + return WPSEO_Meta::get_value( 'metadesc', wc_get_page_id( 'shop' ) ); + } + + /** + * WP SEO meta key. + * + * Hooked into wpseo_ hook already, so no need for function_exist. + * + * @return string + */ + public function wpseo_metakey() { + return WPSEO_Meta::get_value( 'metakey', wc_get_page_id( 'shop' ) ); + } + + /** + * Query the products, applying sorting/ordering etc. + * This applies to the main WordPress loop. + * + * @param WP_Query $q Query instance. + */ + public function product_query( $q ) { + if ( ! is_feed() ) { + $ordering = $this->get_catalog_ordering_args(); + $q->set( 'orderby', $ordering['orderby'] ); + $q->set( 'order', $ordering['order'] ); + + if ( isset( $ordering['meta_key'] ) ) { + $q->set( 'meta_key', $ordering['meta_key'] ); + } + } + + // Query vars that affect posts shown. + $q->set( 'meta_query', $this->get_meta_query( $q->get( 'meta_query' ), true ) ); + $q->set( 'tax_query', $this->get_tax_query( $q->get( 'tax_query' ), true ) ); + $q->set( 'wc_query', 'product_query' ); + $q->set( 'post__in', array_unique( (array) apply_filters( 'loop_shop_post_in', array() ) ) ); + + // Work out how many products to query. + $q->set( 'posts_per_page', $q->get( 'posts_per_page' ) ? $q->get( 'posts_per_page' ) : apply_filters( 'loop_shop_per_page', wc_get_default_products_per_row() * wc_get_default_product_rows_per_page() ) ); + + // Store reference to this query. + self::$product_query = $q; + + // Additonal hooks to change WP Query. + add_filter( 'posts_clauses', array( $this, 'price_filter_post_clauses' ), 10, 2 ); + add_filter( 'the_posts', array( $this, 'handle_get_posts' ), 10, 2 ); + + do_action( 'woocommerce_product_query', $q, $this ); + } + + /** + * Remove the query. + */ + public function remove_product_query() { + remove_action( 'pre_get_posts', array( $this, 'pre_get_posts' ) ); + } + + /** + * Remove ordering queries. + */ + public function remove_ordering_args() { + remove_filter( 'posts_clauses', array( $this, 'order_by_price_asc_post_clauses' ) ); + remove_filter( 'posts_clauses', array( $this, 'order_by_price_desc_post_clauses' ) ); + remove_filter( 'posts_clauses', array( $this, 'order_by_popularity_post_clauses' ) ); + remove_filter( 'posts_clauses', array( $this, 'order_by_rating_post_clauses' ) ); + } + + /** + * Returns an array of arguments for ordering products based on the selected values. + * + * @param string $orderby Order by param. + * @param string $order Order param. + * @return array + */ + public function get_catalog_ordering_args( $orderby = '', $order = '' ) { + // Get ordering from query string unless defined. + if ( ! $orderby ) { + // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $orderby_value = isset( $_GET['orderby'] ) ? wc_clean( (string) wp_unslash( $_GET['orderby'] ) ) : wc_clean( get_query_var( 'orderby' ) ); + + if ( ! $orderby_value ) { + if ( is_search() ) { + $orderby_value = 'relevance'; + } else { + $orderby_value = apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby', 'menu_order' ) ); + } + } + + // Get order + orderby args from string. + $orderby_value = is_array( $orderby_value ) ? $orderby_value : explode( '-', $orderby_value ); + $orderby = esc_attr( $orderby_value[0] ); + $order = ! empty( $orderby_value[1] ) ? $orderby_value[1] : $order; + } + + // Convert to correct format. + $orderby = strtolower( is_array( $orderby ) ? (string) current( $orderby ) : (string) $orderby ); + $order = strtoupper( is_array( $order ) ? (string) current( $order ) : (string) $order ); + $args = array( + 'orderby' => $orderby, + 'order' => ( 'DESC' === $order ) ? 'DESC' : 'ASC', + 'meta_key' => '', // @codingStandardsIgnoreLine + ); + + switch ( $orderby ) { + case 'id': + $args['orderby'] = 'ID'; + break; + case 'menu_order': + $args['orderby'] = 'menu_order title'; + break; + case 'title': + $args['orderby'] = 'title'; + $args['order'] = ( 'DESC' === $order ) ? 'DESC' : 'ASC'; + break; + case 'relevance': + $args['orderby'] = 'relevance'; + $args['order'] = 'DESC'; + break; + case 'rand': + $args['orderby'] = 'rand'; // @codingStandardsIgnoreLine + break; + case 'date': + $args['orderby'] = 'date ID'; + $args['order'] = ( 'ASC' === $order ) ? 'ASC' : 'DESC'; + break; + case 'price': + $callback = 'DESC' === $order ? 'order_by_price_desc_post_clauses' : 'order_by_price_asc_post_clauses'; + add_filter( 'posts_clauses', array( $this, $callback ) ); + break; + case 'popularity': + add_filter( 'posts_clauses', array( $this, 'order_by_popularity_post_clauses' ) ); + break; + case 'rating': + add_filter( 'posts_clauses', array( $this, 'order_by_rating_post_clauses' ) ); + break; + } + + return apply_filters( 'woocommerce_get_catalog_ordering_args', $args, $orderby, $order ); + } + + /** + * Custom query used to filter products by price. + * + * @since 3.6.0 + * + * @param array $args Query args. + * @param WP_Query $wp_query WP_Query object. + * + * @return array + */ + public function price_filter_post_clauses( $args, $wp_query ) { + global $wpdb; + + // phpcs:ignore WordPress.Security.NonceVerification.Recommended + if ( ! $wp_query->is_main_query() || ( ! isset( $_GET['max_price'] ) && ! isset( $_GET['min_price'] ) ) ) { + return $args; + } + + // phpcs:disable WordPress.Security.NonceVerification.Recommended + $current_min_price = isset( $_GET['min_price'] ) ? floatval( wp_unslash( $_GET['min_price'] ) ) : 0; + $current_max_price = isset( $_GET['max_price'] ) ? floatval( wp_unslash( $_GET['max_price'] ) ) : PHP_INT_MAX; + // phpcs:enable WordPress.Security.NonceVerification.Recommended + + /** + * Adjust if the store taxes are not displayed how they are stored. + * Kicks in when prices excluding tax are displayed including tax. + */ + if ( wc_tax_enabled() && 'incl' === get_option( 'woocommerce_tax_display_shop' ) && ! wc_prices_include_tax() ) { + $tax_class = apply_filters( 'woocommerce_price_filter_widget_tax_class', '' ); // Uses standard tax class. + $tax_rates = WC_Tax::get_rates( $tax_class ); + + if ( $tax_rates ) { + $current_min_price -= WC_Tax::get_tax_total( WC_Tax::calc_inclusive_tax( $current_min_price, $tax_rates ) ); + $current_max_price -= WC_Tax::get_tax_total( WC_Tax::calc_inclusive_tax( $current_max_price, $tax_rates ) ); + } + } + + $args['join'] = $this->append_product_sorting_table_join( $args['join'] ); + $args['where'] .= $wpdb->prepare( + ' AND wc_product_meta_lookup.min_price >= %f AND wc_product_meta_lookup.max_price <= %f ', + $current_min_price, + $current_max_price + ); + return $args; + } + + /** + * Handle numeric price sorting. + * + * @param array $args Query args. + * @return array + */ + public function order_by_price_asc_post_clauses( $args ) { + $args['join'] = $this->append_product_sorting_table_join( $args['join'] ); + $args['orderby'] = ' wc_product_meta_lookup.min_price ASC, wc_product_meta_lookup.product_id ASC '; + return $args; + } + + /** + * Handle numeric price sorting. + * + * @param array $args Query args. + * @return array + */ + public function order_by_price_desc_post_clauses( $args ) { + $args['join'] = $this->append_product_sorting_table_join( $args['join'] ); + $args['orderby'] = ' wc_product_meta_lookup.max_price DESC, wc_product_meta_lookup.product_id DESC '; + return $args; + } + + /** + * WP Core does not let us change the sort direction for individual orderby params - https://core.trac.wordpress.org/ticket/17065. + * + * This lets us sort by meta value desc, and have a second orderby param. + * + * @param array $args Query args. + * @return array + */ + public function order_by_popularity_post_clauses( $args ) { + $args['join'] = $this->append_product_sorting_table_join( $args['join'] ); + $args['orderby'] = ' wc_product_meta_lookup.total_sales DESC, wc_product_meta_lookup.product_id DESC '; + return $args; + } + + /** + * Order by rating post clauses. + * + * @param array $args Query args. + * @return array + */ + public function order_by_rating_post_clauses( $args ) { + $args['join'] = $this->append_product_sorting_table_join( $args['join'] ); + $args['orderby'] = ' wc_product_meta_lookup.average_rating DESC, wc_product_meta_lookup.rating_count DESC, wc_product_meta_lookup.product_id DESC '; + return $args; + } + + /** + * Join wc_product_meta_lookup to posts if not already joined. + * + * @param string $sql SQL join. + * @return string + */ + private function append_product_sorting_table_join( $sql ) { + global $wpdb; + + if ( ! strstr( $sql, 'wc_product_meta_lookup' ) ) { + $sql .= " LEFT JOIN {$wpdb->wc_product_meta_lookup} wc_product_meta_lookup ON $wpdb->posts.ID = wc_product_meta_lookup.product_id "; + } + return $sql; + } + + /** + * Appends meta queries to an array. + * + * @param array $meta_query Meta query. + * @param bool $main_query If is main query. + * @return array + */ + public function get_meta_query( $meta_query = array(), $main_query = false ) { + if ( ! is_array( $meta_query ) ) { + $meta_query = array(); + } + return array_filter( apply_filters( 'woocommerce_product_query_meta_query', $meta_query, $this ) ); + } + + /** + * Appends tax queries to an array. + * + * @param array $tax_query Tax query. + * @param bool $main_query If is main query. + * @return array + */ + public function get_tax_query( $tax_query = array(), $main_query = false ) { + if ( ! is_array( $tax_query ) ) { + $tax_query = array( + 'relation' => 'AND', + ); + } + + // Layered nav filters on terms. + if ( $main_query ) { + foreach ( $this->get_layered_nav_chosen_attributes() as $taxonomy => $data ) { + $tax_query[] = array( + 'taxonomy' => $taxonomy, + 'field' => 'slug', + 'terms' => $data['terms'], + 'operator' => 'and' === $data['query_type'] ? 'AND' : 'IN', + 'include_children' => false, + ); + } + } + + $product_visibility_terms = wc_get_product_visibility_term_ids(); + $product_visibility_not_in = array( is_search() && $main_query ? $product_visibility_terms['exclude-from-search'] : $product_visibility_terms['exclude-from-catalog'] ); + + // Hide out of stock products. + if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) { + $product_visibility_not_in[] = $product_visibility_terms['outofstock']; + } + + // phpcs:disable WordPress.Security.NonceVerification.Recommended + // Filter by rating. + if ( isset( $_GET['rating_filter'] ) ) { + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + $rating_filter = array_filter( array_map( 'absint', explode( ',', wp_unslash( $_GET['rating_filter'] ) ) ) ); + $rating_terms = array(); + for ( $i = 1; $i <= 5; $i ++ ) { + if ( in_array( $i, $rating_filter, true ) && isset( $product_visibility_terms[ 'rated-' . $i ] ) ) { + $rating_terms[] = $product_visibility_terms[ 'rated-' . $i ]; + } + } + if ( ! empty( $rating_terms ) ) { + $tax_query[] = array( + 'taxonomy' => 'product_visibility', + 'field' => 'term_taxonomy_id', + 'terms' => $rating_terms, + 'operator' => 'IN', + 'rating_filter' => true, + ); + } + } + // phpcs:enable WordPress.Security.NonceVerification.Recommended + + if ( ! empty( $product_visibility_not_in ) ) { + $tax_query[] = array( + 'taxonomy' => 'product_visibility', + 'field' => 'term_taxonomy_id', + 'terms' => $product_visibility_not_in, + 'operator' => 'NOT IN', + ); + } + + return array_filter( apply_filters( 'woocommerce_product_query_tax_query', $tax_query, $this ) ); + } + + /** + * Get the main query which product queries ran against. + * + * @return WP_Query + */ + public static function get_main_query() { + return self::$product_query; + } + + /** + * Get the tax query which was used by the main query. + * + * @return array + */ + public static function get_main_tax_query() { + $tax_query = isset( self::$product_query->tax_query, self::$product_query->tax_query->queries ) ? self::$product_query->tax_query->queries : array(); + + return $tax_query; + } + + /** + * Get the meta query which was used by the main query. + * + * @return array + */ + public static function get_main_meta_query() { + $args = self::$product_query->query_vars; + $meta_query = isset( $args['meta_query'] ) ? $args['meta_query'] : array(); + + return $meta_query; + } + + /** + * Based on WP_Query::parse_search + */ + public static function get_main_search_query_sql() { + global $wpdb; + + $args = self::$product_query->query_vars; + $search_terms = isset( $args['search_terms'] ) ? $args['search_terms'] : array(); + $sql = array(); + + foreach ( $search_terms as $term ) { + // Terms prefixed with '-' should be excluded. + $include = '-' !== substr( $term, 0, 1 ); + + if ( $include ) { + $like_op = 'LIKE'; + $andor_op = 'OR'; + } else { + $like_op = 'NOT LIKE'; + $andor_op = 'AND'; + $term = substr( $term, 1 ); + } + + $like = '%' . $wpdb->esc_like( $term ) . '%'; + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared + $sql[] = $wpdb->prepare( "(($wpdb->posts.post_title $like_op %s) $andor_op ($wpdb->posts.post_excerpt $like_op %s) $andor_op ($wpdb->posts.post_content $like_op %s))", $like, $like, $like ); + } + + if ( ! empty( $sql ) && ! is_user_logged_in() ) { + $sql[] = "($wpdb->posts.post_password = '')"; + } + + return implode( ' AND ', $sql ); + } + + /** + * Get an array of attributes and terms selected with the layered nav widget. + * + * @return array + */ + public static function get_layered_nav_chosen_attributes() { + // phpcs:disable WordPress.Security.NonceVerification.Recommended + if ( ! is_array( self::$chosen_attributes ) ) { + self::$chosen_attributes = array(); + + if ( ! empty( $_GET ) ) { + foreach ( $_GET as $key => $value ) { + if ( 0 === strpos( $key, 'filter_' ) ) { + $attribute = wc_sanitize_taxonomy_name( str_replace( 'filter_', '', $key ) ); + $taxonomy = wc_attribute_taxonomy_name( $attribute ); + $filter_terms = ! empty( $value ) ? explode( ',', wc_clean( wp_unslash( $value ) ) ) : array(); + + if ( empty( $filter_terms ) || ! taxonomy_exists( $taxonomy ) || ! wc_attribute_taxonomy_id_by_name( $attribute ) ) { + continue; + } + + $query_type = ! empty( $_GET[ 'query_type_' . $attribute ] ) && in_array( $_GET[ 'query_type_' . $attribute ], array( 'and', 'or' ), true ) ? wc_clean( wp_unslash( $_GET[ 'query_type_' . $attribute ] ) ) : ''; + self::$chosen_attributes[ $taxonomy ]['terms'] = array_map( 'sanitize_title', $filter_terms ); // Ensures correct encoding. + self::$chosen_attributes[ $taxonomy ]['query_type'] = $query_type ? $query_type : apply_filters( 'woocommerce_layered_nav_default_query_type', 'and' ); + } + } + } + } + return self::$chosen_attributes; + // phpcs:disable WordPress.Security.NonceVerification.Recommended + } + + /** + * Remove the add-to-cart param from pagination urls. + * + * @param string $url URL. + * @return string + */ + public function remove_add_to_cart_pagination( $url ) { + return remove_query_arg( 'add-to-cart', $url ); + } + + /** + * Return a meta query for filtering by rating. + * + * @deprecated 3.0.0 Replaced with taxonomy. + * @return array + */ + public function rating_filter_meta_query() { + return array(); + } + + /** + * Returns a meta query to handle product visibility. + * + * @deprecated 3.0.0 Replaced with taxonomy. + * @param string $compare (default: 'IN'). + * @return array + */ + public function visibility_meta_query( $compare = 'IN' ) { + return array(); + } + + /** + * Returns a meta query to handle product stock status. + * + * @deprecated 3.0.0 Replaced with taxonomy. + * @param string $status (default: 'instock'). + * @return array + */ + public function stock_status_meta_query( $status = 'instock' ) { + return array(); + } + + /** + * Layered nav init. + * + * @deprecated 2.6.0 + */ + public function layered_nav_init() { + wc_deprecated_function( 'layered_nav_init', '2.6' ); + } + + /** + * Get an unpaginated list all product IDs (both filtered and unfiltered). Makes use of transients. + * + * @deprecated 2.6.0 due to performance concerns + */ + public function get_products_in_view() { + wc_deprecated_function( 'get_products_in_view', '2.6' ); + } + + /** + * Layered Nav post filter. + * + * @deprecated 2.6.0 due to performance concerns + * + * @param mixed $deprecated Deprecated. + */ + public function layered_nav_query( $deprecated ) { + wc_deprecated_function( 'layered_nav_query', '2.6' ); + } + + /** + * Search post excerpt. + * + * @param string $where Where clause. + * + * @deprecated 3.2.0 - Not needed anymore since WordPress 4.5. + */ + public function search_post_excerpt( $where = '' ) { + wc_deprecated_function( 'WC_Query::search_post_excerpt', '3.2.0', 'Excerpt added to search query by default since WordPress 4.5.' ); + return $where; + } + + /** + * Remove the posts_where filter. + * + * @deprecated 3.2.0 - Nothing to remove anymore because search_post_excerpt() is deprecated. + */ + public function remove_posts_where() { + wc_deprecated_function( 'WC_Query::remove_posts_where', '3.2.0', 'Nothing to remove anymore because search_post_excerpt() is deprecated.' ); + } +} diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-rate-limiter.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-rate-limiter.php new file mode 100644 index 0000000..aba4fb0 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-rate-limiter.php @@ -0,0 +1,79 @@ +prefix = 'wp_' . get_current_blog_id(); + $this->action = 'wc_regenerate_images'; + + // This is needed to prevent timeouts due to threading. See https://core.trac.wordpress.org/ticket/36534. + @putenv( 'MAGICK_THREAD_LIMIT=1' ); // @codingStandardsIgnoreLine. + + parent::__construct(); + } + + /** + * Is job running? + * + * @return boolean + */ + public function is_running() { + return $this->is_queue_empty(); + } + + /** + * Limit each task ran per batch to 1 for image regen. + * + * @return bool + */ + protected function batch_limit_exceeded() { + return true; + } + + /** + * Determines whether an attachment can have its thumbnails regenerated. + * + * Adapted from Regenerate Thumbnails by Alex Mills. + * + * @param WP_Post $attachment An attachment's post object. + * @return bool Whether the given attachment can have its thumbnails regenerated. + */ + protected function is_regeneratable( $attachment ) { + if ( 'site-icon' === get_post_meta( $attachment->ID, '_wp_attachment_context', true ) ) { + return false; + } + + if ( wp_attachment_is_image( $attachment ) ) { + return true; + } + + return false; + } + + /** + * Code to execute for each item in the queue + * + * @param mixed $item Queue item to iterate over. + * @return bool + */ + protected function task( $item ) { + if ( ! is_array( $item ) && ! isset( $item['attachment_id'] ) ) { + return false; + } + + $this->attachment_id = absint( $item['attachment_id'] ); + $attachment = get_post( $this->attachment_id ); + + if ( ! $attachment || 'attachment' !== $attachment->post_type || ! $this->is_regeneratable( $attachment ) ) { + return false; + } + + if ( ! function_exists( 'wp_crop_image' ) ) { + include ABSPATH . 'wp-admin/includes/image.php'; + } + + $log = wc_get_logger(); + + $log->info( + sprintf( + // translators: %s: ID of the attachment. + __( 'Regenerating images for attachment ID: %s', 'woocommerce' ), + $this->attachment_id + ), + array( + 'source' => 'wc-image-regeneration', + ) + ); + + $fullsizepath = get_attached_file( $this->attachment_id ); + + // Check if the file exists, if not just remove item from queue. + if ( false === $fullsizepath || is_wp_error( $fullsizepath ) || ! file_exists( $fullsizepath ) ) { + return false; + } + + $old_metadata = wp_get_attachment_metadata( $this->attachment_id ); + + // We only want to regen WC images. + add_filter( 'intermediate_image_sizes', array( $this, 'adjust_intermediate_image_sizes' ) ); + + // We only want to resize images if they do not already exist. + add_filter( 'intermediate_image_sizes_advanced', array( $this, 'filter_image_sizes_to_only_missing_thumbnails' ), 10, 3 ); + + // This function will generate the new image sizes. + $new_metadata = wp_generate_attachment_metadata( $this->attachment_id, $fullsizepath ); + + // Remove custom filters. + remove_filter( 'intermediate_image_sizes', array( $this, 'adjust_intermediate_image_sizes' ) ); + remove_filter( 'intermediate_image_sizes_advanced', array( $this, 'filter_image_sizes_to_only_missing_thumbnails' ), 10, 3 ); + + // If something went wrong lets just remove the item from the queue. + if ( is_wp_error( $new_metadata ) || empty( $new_metadata ) ) { + return false; + } + + if ( ! empty( $old_metadata ) && ! empty( $old_metadata['sizes'] ) && is_array( $old_metadata['sizes'] ) ) { + foreach ( $old_metadata['sizes'] as $old_size => $old_size_data ) { + if ( empty( $new_metadata['sizes'][ $old_size ] ) ) { + $new_metadata['sizes'][ $old_size ] = $old_metadata['sizes'][ $old_size ]; + } + } + // Handle legacy sizes. + if ( isset( $new_metadata['sizes']['shop_thumbnail'], $new_metadata['sizes']['woocommerce_gallery_thumbnail'] ) ) { + $new_metadata['sizes']['shop_thumbnail'] = $new_metadata['sizes']['woocommerce_gallery_thumbnail']; + } + if ( isset( $new_metadata['sizes']['shop_catalog'], $new_metadata['sizes']['woocommerce_thumbnail'] ) ) { + $new_metadata['sizes']['shop_catalog'] = $new_metadata['sizes']['woocommerce_thumbnail']; + } + if ( isset( $new_metadata['sizes']['shop_single'], $new_metadata['sizes']['woocommerce_single'] ) ) { + $new_metadata['sizes']['shop_single'] = $new_metadata['sizes']['woocommerce_single']; + } + } + + // Update the meta data with the new size values. + wp_update_attachment_metadata( $this->attachment_id, $new_metadata ); + + // We made it till the end, now lets remove the item from the queue. + return false; + } + + /** + * Filters the list of thumbnail sizes to only include those which have missing files. + * + * @param array $sizes An associative array of registered thumbnail image sizes. + * @param array $metadata An associative array of fullsize image metadata: width, height, file. + * @param int $attachment_id Attachment ID. Only passed from WP 5.0+. + * @return array An associative array of image sizes. + */ + public function filter_image_sizes_to_only_missing_thumbnails( $sizes, $metadata, $attachment_id = null ) { + $attachment_id = is_null( $attachment_id ) ? $this->attachment_id : $attachment_id; + + if ( ! $sizes || ! $attachment_id ) { + return $sizes; + } + + $fullsizepath = get_attached_file( $attachment_id ); + $editor = wp_get_image_editor( $fullsizepath ); + + if ( is_wp_error( $editor ) ) { + return $sizes; + } + + $metadata = wp_get_attachment_metadata( $attachment_id ); + + // This is based on WP_Image_Editor_GD::multi_resize() and others. + foreach ( $sizes as $size => $size_data ) { + if ( empty( $metadata['sizes'][ $size ] ) ) { + continue; + } + if ( ! isset( $size_data['width'] ) && ! isset( $size_data['height'] ) ) { + continue; + } + if ( ! isset( $size_data['width'] ) ) { + $size_data['width'] = null; + } + if ( ! isset( $size_data['height'] ) ) { + $size_data['height'] = null; + } + if ( ! isset( $size_data['crop'] ) ) { + $size_data['crop'] = false; + } + + $image_sizes = getimagesize( $fullsizepath ); + if ( false === $image_sizes ) { + continue; + } + list( $orig_w, $orig_h ) = $image_sizes; + + $dimensions = image_resize_dimensions( $orig_w, $orig_h, $size_data['width'], $size_data['height'], $size_data['crop'] ); + + if ( ! $dimensions || ! is_array( $dimensions ) ) { + continue; + } + + $info = pathinfo( $fullsizepath ); + $ext = $info['extension']; + $dst_w = $dimensions[4]; + $dst_h = $dimensions[5]; + $suffix = "{$dst_w}x{$dst_h}"; + $dst_rel_path = str_replace( '.' . $ext, '', $fullsizepath ); + $thumbnail = "{$dst_rel_path}-{$suffix}.{$ext}"; + + if ( $dst_w === $metadata['sizes'][ $size ]['width'] && $dst_h === $metadata['sizes'][ $size ]['height'] && file_exists( $thumbnail ) ) { + unset( $sizes[ $size ] ); + } + } + + return $sizes; + } + + /** + * Returns the sizes we want to regenerate. + * + * @param array $sizes Sizes to generate. + * @return array + */ + public function adjust_intermediate_image_sizes( $sizes ) { + // Prevent a filter loop. + $unfiltered_sizes = array( 'woocommerce_thumbnail', 'woocommerce_gallery_thumbnail', 'woocommerce_single' ); + static $in_filter = false; + if ( $in_filter ) { + return $unfiltered_sizes; + } + $in_filter = true; + $filtered_sizes = apply_filters( 'woocommerce_regenerate_images_intermediate_image_sizes', $unfiltered_sizes ); + $in_filter = false; + return $filtered_sizes; + } + + /** + * This runs once the job has completed all items on the queue. + * + * @return void + */ + protected function complete() { + parent::complete(); + $log = wc_get_logger(); + $log->info( + __( 'Completed product image regeneration job.', 'woocommerce' ), + array( + 'source' => 'wc-image-regeneration', + ) + ); + } +} diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-regenerate-images.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-regenerate-images.php new file mode 100644 index 0000000..6e6ed20 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-regenerate-images.php @@ -0,0 +1,471 @@ +is_running() ) { + WC_Admin_Notices::add_notice( 'regenerating_thumbnails' ); + } else { + WC_Admin_Notices::remove_notice( 'regenerating_thumbnails' ); + } + } + + /** + * Dismiss notice and cancel jobs. + */ + public static function dismiss_regenerating_notice() { + if ( self::$background_process ) { + self::$background_process->kill_process(); + + $log = wc_get_logger(); + $log->info( + __( 'Cancelled product image regeneration job.', 'woocommerce' ), + array( + 'source' => 'wc-image-regeneration', + ) + ); + } + WC_Admin_Notices::remove_notice( 'regenerating_thumbnails' ); + } + + /** + * Regenerate images if the settings have changed since last re-generation. + * + * @return void + */ + public static function maybe_regenerate_images() { + $size_hash = md5( + wp_json_encode( + array( + wc_get_image_size( 'thumbnail' ), + wc_get_image_size( 'single' ), + wc_get_image_size( 'gallery_thumbnail' ), + ) + ) + ); + + if ( update_option( 'woocommerce_maybe_regenerate_images_hash', $size_hash ) ) { + // Size settings have changed. Trigger regen. + self::queue_image_regeneration(); + } + } + + /** + * Check if we should maybe generate a new image size if not already there. + * + * @param array $image Properties of the image. + * @param int $attachment_id Attachment ID. + * @param string|array $size Image size. + * @param bool $icon If icon or not. + * @return array + */ + public static function maybe_resize_image( $image, $attachment_id, $size, $icon ) { + if ( ! apply_filters( 'woocommerce_resize_images', true ) ) { + return $image; + } + + // List of sizes we want to resize. Ignore others. + if ( ! $image || ! in_array( $size, apply_filters( 'woocommerce_image_sizes_to_resize', array( 'woocommerce_thumbnail', 'woocommerce_gallery_thumbnail', 'woocommerce_single', 'shop_thumbnail', 'shop_catalog', 'shop_single' ) ), true ) ) { + return $image; + } + + $target_size = wc_get_image_size( $size ); + $image_width = $image[1]; + $image_height = $image[2]; + $ratio_match = false; + $target_uncropped = '' === $target_size['width'] || '' === $target_size['height'] || ! $target_size['crop']; + + // If '' is passed to either size, we test ratios against the original file. It's uncropped. + if ( $target_uncropped ) { + $full_size = self::get_full_size_image_dimensions( $attachment_id ); + + if ( ! $full_size || ! $full_size['width'] || ! $full_size['height'] ) { + return $image; + } + + $ratio_match = wp_image_matches_ratio( $image_width, $image_height, $full_size['width'], $full_size['height'] ); + } else { + $ratio_match = wp_image_matches_ratio( $image_width, $image_height, $target_size['width'], $target_size['height'] ); + } + + if ( ! $ratio_match ) { + $full_size = self::get_full_size_image_dimensions( $attachment_id ); + + if ( ! $full_size ) { + return $image; + } + + // Check if the actual image has a larger dimension than the requested image size. Smaller images are not zoom-cropped. + if ( $image_width === $target_size['width'] && $full_size['height'] < $target_size['height'] ) { + return $image; + } + + if ( $image_height === $target_size['height'] && $full_size['width'] < $target_size['width'] ) { + return $image; + } + + // If the full size image is smaller both ways, don't scale it up. + if ( $full_size['height'] < $target_size['height'] && $full_size['width'] < $target_size['width'] ) { + return $image; + } + + return self::resize_and_return_image( $attachment_id, $image, $size, $icon ); + } + + return $image; + } + + /** + * Get full size image dimensions. + * + * @param int $attachment_id Attachment ID of image. + * @return array Width and height. Empty array if the dimensions cannot be found. + */ + private static function get_full_size_image_dimensions( $attachment_id ) { + $imagedata = wp_get_attachment_metadata( $attachment_id ); + + if ( ! $imagedata ) { + return array(); + } + + if ( ! isset( $imagedata['file'] ) && isset( $imagedata['sizes']['full'] ) ) { + $imagedata['height'] = $imagedata['sizes']['full']['height']; + $imagedata['width'] = $imagedata['sizes']['full']['width']; + } + + return array( + 'width' => $imagedata['width'], + 'height' => $imagedata['height'], + ); + } + + /** + * Ensure we are dealing with the correct image attachment + * + * @param int|WP_Post $attachment Attachment object or ID. + * @return boolean + */ + public static function is_regeneratable( $attachment ) { + if ( 'site-icon' === get_post_meta( is_object( $attachment ) ? $attachment->ID : $attachment, '_wp_attachment_context', true ) ) { + return false; + } + + if ( wp_attachment_is_image( $attachment ) ) { + return true; + } + + return false; + } + + /** + * Only regenerate images for the requested size. + * + * @param array $sizes Array of image sizes. + * @return array + */ + public static function adjust_intermediate_image_sizes( $sizes ) { + return array( self::$regenerate_size ); + } + + /** + * Generate the thumbnail filename and dimensions for a given file. + * + * @param string $fullsizepath Path to full size image. + * @param int $thumbnail_width The width of the thumbnail. + * @param int $thumbnail_height The height of the thumbnail. + * @param bool $crop Whether to crop or not. + * @return array|false An array of the filename, thumbnail width, and thumbnail height, or false on failure to resize such as the thumbnail being larger than the fullsize image. + */ + private static function get_image( $fullsizepath, $thumbnail_width, $thumbnail_height, $crop ) { + list( $fullsize_width, $fullsize_height ) = getimagesize( $fullsizepath ); + + $dimensions = image_resize_dimensions( $fullsize_width, $fullsize_height, $thumbnail_width, $thumbnail_height, $crop ); + $editor = wp_get_image_editor( $fullsizepath ); + + if ( is_wp_error( $editor ) ) { + return false; + } + + if ( ! $dimensions || ! is_array( $dimensions ) ) { + return false; + } + + list( , , , , $dst_w, $dst_h ) = $dimensions; + $suffix = "{$dst_w}x{$dst_h}"; + $file_ext = strtolower( pathinfo( $fullsizepath, PATHINFO_EXTENSION ) ); + + return array( + 'filename' => $editor->generate_filename( $suffix, null, $file_ext ), + 'width' => $dst_w, + 'height' => $dst_h, + ); + } + + /** + * Regenerate the image according to the required size + * + * @param int $attachment_id Attachment ID. + * @param array $image Original Image. + * @param string $size Size to return for new URL. + * @param bool $icon If icon or not. + * @return string + */ + private static function resize_and_return_image( $attachment_id, $image, $size, $icon ) { + if ( ! self::is_regeneratable( $attachment_id ) ) { + return $image; + } + + $fullsizepath = get_attached_file( $attachment_id ); + + if ( false === $fullsizepath || is_wp_error( $fullsizepath ) || ! file_exists( $fullsizepath ) ) { + return $image; + } + + if ( ! function_exists( 'wp_crop_image' ) ) { + include ABSPATH . 'wp-admin/includes/image.php'; + } + + self::$regenerate_size = is_customize_preview() ? $size . '_preview' : $size; + + if ( is_customize_preview() ) { + $image_size = wc_get_image_size( $size ); + + // Make sure registered image size matches the size we're requesting. + add_image_size( self::$regenerate_size, absint( $image_size['width'] ), absint( $image_size['height'] ), $image_size['crop'] ); + + $thumbnail = self::get_image( $fullsizepath, absint( $image_size['width'] ), absint( $image_size['height'] ), $image_size['crop'] ); + + // If the file is already there perhaps just load it if we're using the customizer. No need to store in meta data. + if ( $thumbnail && file_exists( $thumbnail['filename'] ) ) { + $wp_uploads = wp_upload_dir( null, false ); + $wp_uploads_dir = $wp_uploads['basedir']; + $wp_uploads_url = $wp_uploads['baseurl']; + + return array( + 0 => str_replace( $wp_uploads_dir, $wp_uploads_url, $thumbnail['filename'] ), + 1 => $thumbnail['width'], + 2 => $thumbnail['height'], + ); + } + } + + $metadata = wp_get_attachment_metadata( $attachment_id ); + + // Fix for images with no metadata. + if ( ! is_array( $metadata ) ) { + $metadata = array(); + } + + // We only want to regen a specific image size. + add_filter( 'intermediate_image_sizes', array( __CLASS__, 'adjust_intermediate_image_sizes' ) ); + + // This function will generate the new image sizes. + $new_metadata = wp_generate_attachment_metadata( $attachment_id, $fullsizepath ); + + // Remove custom filter. + remove_filter( 'intermediate_image_sizes', array( __CLASS__, 'adjust_intermediate_image_sizes' ) ); + + // If something went wrong lets just return the original image. + if ( is_wp_error( $new_metadata ) || empty( $new_metadata ) ) { + return $image; + } + + if ( isset( $new_metadata['sizes'][ self::$regenerate_size ] ) ) { + $metadata['sizes'][ self::$regenerate_size ] = $new_metadata['sizes'][ self::$regenerate_size ]; + wp_update_attachment_metadata( $attachment_id, $metadata ); + } + + // Now we've done our regen, attempt to return the new size. + $new_image = self::unfiltered_image_downsize( $attachment_id, self::$regenerate_size ); + + return $new_image ? $new_image : $image; + } + + /** + * Image downsize, without this classes filtering on the results. + * + * @param int $attachment_id Attachment ID. + * @param string $size Size to downsize to. + * @return string New image URL. + */ + private static function unfiltered_image_downsize( $attachment_id, $size ) { + remove_action( 'image_get_intermediate_size', array( __CLASS__, 'filter_image_get_intermediate_size' ), 10, 3 ); + + $return = image_downsize( $attachment_id, $size ); + + add_action( 'image_get_intermediate_size', array( __CLASS__, 'filter_image_get_intermediate_size' ), 10, 3 ); + + return $return; + } + + /** + * Get list of images and queue them for regeneration + * + * @return void + */ + public static function queue_image_regeneration() { + global $wpdb; + // First lets cancel existing running queue to avoid running it more than once. + self::$background_process->kill_process(); + + // Now lets find all product image attachments IDs and pop them onto the queue. + $images = $wpdb->get_results( // @codingStandardsIgnoreLine + "SELECT ID + FROM $wpdb->posts + WHERE post_type = 'attachment' + AND post_mime_type LIKE 'image/%' + ORDER BY ID DESC" + ); + foreach ( $images as $image ) { + self::$background_process->push_to_queue( + array( + 'attachment_id' => $image->ID, + ) + ); + } + + // Lets dispatch the queue to start processing. + self::$background_process->save()->dispatch(); + } +} + +add_action( 'init', array( 'WC_Regenerate_Images', 'init' ) ); diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-register-wp-admin-settings.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-register-wp-admin-settings.php new file mode 100644 index 0000000..9dbefe8 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-register-wp-admin-settings.php @@ -0,0 +1,180 @@ +object = $object; + + if ( 'page' === $type ) { + add_filter( 'woocommerce_settings_groups', array( $this, 'register_page_group' ) ); + add_filter( 'woocommerce_settings-' . $this->object->get_id(), array( $this, 'register_page_settings' ) ); + } elseif ( 'email' === $type ) { + add_filter( 'woocommerce_settings_groups', array( $this, 'register_email_group' ) ); + add_filter( 'woocommerce_settings-email_' . $this->object->id, array( $this, 'register_email_settings' ) ); + } + } + + /** + * Register's all of our different notification emails as sub groups + * of email settings. + * + * @since 3.0.0 + * @param array $groups Existing registered groups. + * @return array + */ + public function register_email_group( $groups ) { + $groups[] = array( + 'id' => 'email_' . $this->object->id, + 'label' => $this->object->title, + 'description' => $this->object->description, + 'parent_id' => 'email', + ); + return $groups; + } + + /** + * Registers all of the setting form fields for emails to each email type's group. + * + * @since 3.0.0 + * @param array $settings Existing registered settings. + * @return array + */ + public function register_email_settings( $settings ) { + foreach ( $this->object->form_fields as $id => $setting ) { + $setting['id'] = $id; + $setting['option_key'] = array( $this->object->get_option_key(), $id ); + $new_setting = $this->register_setting( $setting ); + if ( $new_setting ) { + $settings[] = $new_setting; + } + } + return $settings; + } + + /** + * Registers a setting group, based on admin page ID & label as parent group. + * + * @since 3.0.0 + * @param array $groups Array of previously registered groups. + * @return array + */ + public function register_page_group( $groups ) { + $groups[] = array( + 'id' => $this->object->get_id(), + 'label' => $this->object->get_label(), + ); + return $groups; + } + + /** + * Registers settings to a specific group. + * + * @since 3.0.0 + * @param array $settings Existing registered settings. + * @return array + */ + public function register_page_settings( $settings ) { + /** + * WP admin settings can be broken down into separate sections from + * a UI standpoint. This will grab all the sections associated with + * a particular setting group (like 'products') and register them + * to the REST API. + */ + $sections = $this->object->get_sections(); + if ( empty( $sections ) ) { + // Default section is just an empty string, per admin page classes. + $sections = array( '' ); + } + + foreach ( $sections as $section => $section_label ) { + $settings_from_section = $this->object->get_settings( $section ); + foreach ( $settings_from_section as $setting ) { + if ( ! isset( $setting['id'] ) ) { + continue; + } + $setting['option_key'] = $setting['id']; + $new_setting = $this->register_setting( $setting ); + if ( $new_setting ) { + $settings[] = $new_setting; + } + } + } + return $settings; + } + + /** + * Register a setting into the format expected for the Settings REST API. + * + * @since 3.0.0 + * @param array $setting Setting data. + * @return array|bool + */ + public function register_setting( $setting ) { + if ( ! isset( $setting['id'] ) ) { + return false; + } + + $description = ''; + if ( ! empty( $setting['desc'] ) ) { + $description = $setting['desc']; + } elseif ( ! empty( $setting['description'] ) ) { + $description = $setting['description']; + } + + $new_setting = array( + 'id' => $setting['id'], + 'label' => ( ! empty( $setting['title'] ) ? $setting['title'] : '' ), + 'description' => $description, + 'type' => $setting['type'], + 'option_key' => $setting['option_key'], + ); + + if ( isset( $setting['default'] ) ) { + $new_setting['default'] = $setting['default']; + } + if ( isset( $setting['options'] ) ) { + $new_setting['options'] = $setting['options']; + } + if ( isset( $setting['desc_tip'] ) ) { + if ( true === $setting['desc_tip'] ) { + $new_setting['tip'] = $description; + } elseif ( ! empty( $setting['desc_tip'] ) ) { + $new_setting['tip'] = $setting['desc_tip']; + } + } + + return $new_setting; + } + +} diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-rest-authentication.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-rest-authentication.php new file mode 100644 index 0000000..d31cad0 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-rest-authentication.php @@ -0,0 +1,640 @@ +is_request_to_rest_api() ) { + return $user_id; + } + + if ( is_ssl() ) { + $user_id = $this->perform_basic_authentication(); + } + + if ( $user_id ) { + return $user_id; + } + + return $this->perform_oauth_authentication(); + } + + /** + * Authenticate the user if authentication wasn't performed during the + * determine_current_user action. + * + * Necessary in cases where wp_get_current_user() is called before WooCommerce is loaded. + * + * @see https://github.com/woocommerce/woocommerce/issues/26847 + * + * @param WP_Error|null|bool $error Error data. + * @return WP_Error|null|bool + */ + public function authentication_fallback( $error ) { + if ( ! empty( $error ) ) { + // Another plugin has already declared a failure. + return $error; + } + if ( empty( $this->error ) && empty( $this->auth_method ) && empty( $this->user ) && 0 === get_current_user_id() ) { + // Authentication hasn't occurred during `determine_current_user`, so check auth. + $user_id = $this->authenticate( false ); + if ( $user_id ) { + wp_set_current_user( $user_id ); + return true; + } + } + return $error; + } + + /** + * Check for authentication error. + * + * @param WP_Error|null|bool $error Error data. + * @return WP_Error|null|bool + */ + public function check_authentication_error( $error ) { + // Pass through other errors. + if ( ! empty( $error ) ) { + return $error; + } + + return $this->get_error(); + } + + /** + * Set authentication error. + * + * @param WP_Error $error Authentication error data. + */ + protected function set_error( $error ) { + // Reset user. + $this->user = null; + + $this->error = $error; + } + + /** + * Get authentication error. + * + * @return WP_Error|null. + */ + protected function get_error() { + return $this->error; + } + + /** + * Basic Authentication. + * + * SSL-encrypted requests are not subject to sniffing or man-in-the-middle + * attacks, so the request can be authenticated by simply looking up the user + * associated with the given consumer key and confirming the consumer secret + * provided is valid. + * + * @return int|bool + */ + private function perform_basic_authentication() { + $this->auth_method = 'basic_auth'; + $consumer_key = ''; + $consumer_secret = ''; + + // If the $_GET parameters are present, use those first. + if ( ! empty( $_GET['consumer_key'] ) && ! empty( $_GET['consumer_secret'] ) ) { // WPCS: CSRF ok. + $consumer_key = $_GET['consumer_key']; // WPCS: CSRF ok, sanitization ok. + $consumer_secret = $_GET['consumer_secret']; // WPCS: CSRF ok, sanitization ok. + } + + // If the above is not present, we will do full basic auth. + if ( ! $consumer_key && ! empty( $_SERVER['PHP_AUTH_USER'] ) && ! empty( $_SERVER['PHP_AUTH_PW'] ) ) { + $consumer_key = $_SERVER['PHP_AUTH_USER']; // WPCS: CSRF ok, sanitization ok. + $consumer_secret = $_SERVER['PHP_AUTH_PW']; // WPCS: CSRF ok, sanitization ok. + } + + // Stop if don't have any key. + if ( ! $consumer_key || ! $consumer_secret ) { + return false; + } + + // Get user data. + $this->user = $this->get_user_data_by_consumer_key( $consumer_key ); + if ( empty( $this->user ) ) { + return false; + } + + // Validate user secret. + if ( ! hash_equals( $this->user->consumer_secret, $consumer_secret ) ) { // @codingStandardsIgnoreLine + $this->set_error( new WP_Error( 'woocommerce_rest_authentication_error', __( 'Consumer secret is invalid.', 'woocommerce' ), array( 'status' => 401 ) ) ); + + return false; + } + + return $this->user->user_id; + } + + /** + * Parse the Authorization header into parameters. + * + * @since 3.0.0 + * + * @param string $header Authorization header value (not including "Authorization: " prefix). + * + * @return array Map of parameter values. + */ + public function parse_header( $header ) { + if ( 'OAuth ' !== substr( $header, 0, 6 ) ) { + return array(); + } + + // From OAuth PHP library, used under MIT license. + $params = array(); + if ( preg_match_all( '/(oauth_[a-z_-]*)=(:?"([^"]*)"|([^,]*))/', $header, $matches ) ) { + foreach ( $matches[1] as $i => $h ) { + $params[ $h ] = urldecode( empty( $matches[3][ $i ] ) ? $matches[4][ $i ] : $matches[3][ $i ] ); + } + if ( isset( $params['realm'] ) ) { + unset( $params['realm'] ); + } + } + + return $params; + } + + /** + * Get the authorization header. + * + * On certain systems and configurations, the Authorization header will be + * stripped out by the server or PHP. Typically this is then used to + * generate `PHP_AUTH_USER`/`PHP_AUTH_PASS` but not passed on. We use + * `getallheaders` here to try and grab it out instead. + * + * @since 3.0.0 + * + * @return string Authorization header if set. + */ + public function get_authorization_header() { + if ( ! empty( $_SERVER['HTTP_AUTHORIZATION'] ) ) { + return wp_unslash( $_SERVER['HTTP_AUTHORIZATION'] ); // WPCS: sanitization ok. + } + + if ( function_exists( 'getallheaders' ) ) { + $headers = getallheaders(); + // Check for the authoization header case-insensitively. + foreach ( $headers as $key => $value ) { + if ( 'authorization' === strtolower( $key ) ) { + return $value; + } + } + } + + return ''; + } + + /** + * Get oAuth parameters from $_GET, $_POST or request header. + * + * @since 3.0.0 + * + * @return array|WP_Error + */ + public function get_oauth_parameters() { + $params = array_merge( $_GET, $_POST ); // WPCS: CSRF ok. + $params = wp_unslash( $params ); + $header = $this->get_authorization_header(); + + if ( ! empty( $header ) ) { + // Trim leading spaces. + $header = trim( $header ); + $header_params = $this->parse_header( $header ); + + if ( ! empty( $header_params ) ) { + $params = array_merge( $params, $header_params ); + } + } + + $param_names = array( + 'oauth_consumer_key', + 'oauth_timestamp', + 'oauth_nonce', + 'oauth_signature', + 'oauth_signature_method', + ); + + $errors = array(); + $have_one = false; + + // Check for required OAuth parameters. + foreach ( $param_names as $param_name ) { + if ( empty( $params[ $param_name ] ) ) { + $errors[] = $param_name; + } else { + $have_one = true; + } + } + + // All keys are missing, so we're probably not even trying to use OAuth. + if ( ! $have_one ) { + return array(); + } + + // If we have at least one supplied piece of data, and we have an error, + // then it's a failed authentication. + if ( ! empty( $errors ) ) { + $message = sprintf( + /* translators: %s: amount of errors */ + _n( 'Missing OAuth parameter %s', 'Missing OAuth parameters %s', count( $errors ), 'woocommerce' ), + implode( ', ', $errors ) + ); + + $this->set_error( new WP_Error( 'woocommerce_rest_authentication_missing_parameter', $message, array( 'status' => 401 ) ) ); + + return array(); + } + + return $params; + } + + /** + * Perform OAuth 1.0a "one-legged" (http://oauthbible.com/#oauth-10a-one-legged) authentication for non-SSL requests. + * + * This is required so API credentials cannot be sniffed or intercepted when making API requests over plain HTTP. + * + * This follows the spec for simple OAuth 1.0a authentication (RFC 5849) as closely as possible, with two exceptions: + * + * 1) There is no token associated with request/responses, only consumer keys/secrets are used. + * + * 2) The OAuth parameters are included as part of the request query string instead of part of the Authorization header, + * This is because there is no cross-OS function within PHP to get the raw Authorization header. + * + * @link http://tools.ietf.org/html/rfc5849 for the full spec. + * + * @return int|bool + */ + private function perform_oauth_authentication() { + $this->auth_method = 'oauth1'; + + $params = $this->get_oauth_parameters(); + if ( empty( $params ) ) { + return false; + } + + // Fetch WP user by consumer key. + $this->user = $this->get_user_data_by_consumer_key( $params['oauth_consumer_key'] ); + + if ( empty( $this->user ) ) { + $this->set_error( new WP_Error( 'woocommerce_rest_authentication_error', __( 'Consumer key is invalid.', 'woocommerce' ), array( 'status' => 401 ) ) ); + + return false; + } + + // Perform OAuth validation. + $signature = $this->check_oauth_signature( $this->user, $params ); + if ( is_wp_error( $signature ) ) { + $this->set_error( $signature ); + return false; + } + + $timestamp_and_nonce = $this->check_oauth_timestamp_and_nonce( $this->user, $params['oauth_timestamp'], $params['oauth_nonce'] ); + if ( is_wp_error( $timestamp_and_nonce ) ) { + $this->set_error( $timestamp_and_nonce ); + return false; + } + + return $this->user->user_id; + } + + /** + * Verify that the consumer-provided request signature matches our generated signature, + * this ensures the consumer has a valid key/secret. + * + * @param stdClass $user User data. + * @param array $params The request parameters. + * @return true|WP_Error + */ + private function check_oauth_signature( $user, $params ) { + $http_method = isset( $_SERVER['REQUEST_METHOD'] ) ? strtoupper( $_SERVER['REQUEST_METHOD'] ) : ''; // WPCS: sanitization ok. + $request_path = isset( $_SERVER['REQUEST_URI'] ) ? wp_parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH ) : ''; // WPCS: sanitization ok. + $wp_base = get_home_url( null, '/', 'relative' ); + if ( substr( $request_path, 0, strlen( $wp_base ) ) === $wp_base ) { + $request_path = substr( $request_path, strlen( $wp_base ) ); + } + $base_request_uri = rawurlencode( get_home_url( null, $request_path, is_ssl() ? 'https' : 'http' ) ); + + // Get the signature provided by the consumer and remove it from the parameters prior to checking the signature. + $consumer_signature = rawurldecode( str_replace( ' ', '+', $params['oauth_signature'] ) ); + unset( $params['oauth_signature'] ); + + // Sort parameters. + if ( ! uksort( $params, 'strcmp' ) ) { + return new WP_Error( 'woocommerce_rest_authentication_error', __( 'Invalid signature - failed to sort parameters.', 'woocommerce' ), array( 'status' => 401 ) ); + } + + // Normalize parameter key/values. + $params = $this->normalize_parameters( $params ); + $query_string = implode( '%26', $this->join_with_equals_sign( $params ) ); // Join with ampersand. + $string_to_sign = $http_method . '&' . $base_request_uri . '&' . $query_string; + + if ( 'HMAC-SHA1' !== $params['oauth_signature_method'] && 'HMAC-SHA256' !== $params['oauth_signature_method'] ) { + return new WP_Error( 'woocommerce_rest_authentication_error', __( 'Invalid signature - signature method is invalid.', 'woocommerce' ), array( 'status' => 401 ) ); + } + + $hash_algorithm = strtolower( str_replace( 'HMAC-', '', $params['oauth_signature_method'] ) ); + $secret = $user->consumer_secret . '&'; + $signature = base64_encode( hash_hmac( $hash_algorithm, $string_to_sign, $secret, true ) ); + + if ( ! hash_equals( $signature, $consumer_signature ) ) { // @codingStandardsIgnoreLine + return new WP_Error( 'woocommerce_rest_authentication_error', __( 'Invalid signature - provided signature does not match.', 'woocommerce' ), array( 'status' => 401 ) ); + } + + return true; + } + + /** + * Creates an array of urlencoded strings out of each array key/value pairs. + * + * @param array $params Array of parameters to convert. + * @param array $query_params Array to extend. + * @param string $key Optional Array key to append. + * @return string Array of urlencoded strings. + */ + private function join_with_equals_sign( $params, $query_params = array(), $key = '' ) { + foreach ( $params as $param_key => $param_value ) { + if ( $key ) { + $param_key = $key . '%5B' . $param_key . '%5D'; // Handle multi-dimensional array. + } + + if ( is_array( $param_value ) ) { + $query_params = $this->join_with_equals_sign( $param_value, $query_params, $param_key ); + } else { + $string = $param_key . '=' . $param_value; // Join with equals sign. + $query_params[] = wc_rest_urlencode_rfc3986( $string ); + } + } + + return $query_params; + } + + /** + * Normalize each parameter by assuming each parameter may have already been + * encoded, so attempt to decode, and then re-encode according to RFC 3986. + * + * Note both the key and value is normalized so a filter param like: + * + * 'filter[period]' => 'week' + * + * is encoded to: + * + * 'filter%255Bperiod%255D' => 'week' + * + * This conforms to the OAuth 1.0a spec which indicates the entire query string + * should be URL encoded. + * + * @see rawurlencode() + * @param array $parameters Un-normalized parameters. + * @return array Normalized parameters. + */ + private function normalize_parameters( $parameters ) { + $keys = wc_rest_urlencode_rfc3986( array_keys( $parameters ) ); + $values = wc_rest_urlencode_rfc3986( array_values( $parameters ) ); + $parameters = array_combine( $keys, $values ); + + return $parameters; + } + + /** + * Verify that the timestamp and nonce provided with the request are valid. This prevents replay attacks where + * an attacker could attempt to re-send an intercepted request at a later time. + * + * - A timestamp is valid if it is within 15 minutes of now. + * - A nonce is valid if it has not been used within the last 15 minutes. + * + * @param stdClass $user User data. + * @param int $timestamp The unix timestamp for when the request was made. + * @param string $nonce A unique (for the given user) 32 alphanumeric string, consumer-generated. + * @return bool|WP_Error + */ + private function check_oauth_timestamp_and_nonce( $user, $timestamp, $nonce ) { + global $wpdb; + + $valid_window = 15 * 60; // 15 minute window. + + if ( ( $timestamp < time() - $valid_window ) || ( $timestamp > time() + $valid_window ) ) { + return new WP_Error( 'woocommerce_rest_authentication_error', __( 'Invalid timestamp.', 'woocommerce' ), array( 'status' => 401 ) ); + } + + $used_nonces = maybe_unserialize( $user->nonces ); + + if ( empty( $used_nonces ) ) { + $used_nonces = array(); + } + + if ( in_array( $nonce, $used_nonces, true ) ) { + return new WP_Error( 'woocommerce_rest_authentication_error', __( 'Invalid nonce - nonce has already been used.', 'woocommerce' ), array( 'status' => 401 ) ); + } + + $used_nonces[ $timestamp ] = $nonce; + + // Remove expired nonces. + foreach ( $used_nonces as $nonce_timestamp => $nonce ) { + if ( $nonce_timestamp < ( time() - $valid_window ) ) { + unset( $used_nonces[ $nonce_timestamp ] ); + } + } + + $used_nonces = maybe_serialize( $used_nonces ); + + $wpdb->update( + $wpdb->prefix . 'woocommerce_api_keys', + array( 'nonces' => $used_nonces ), + array( 'key_id' => $user->key_id ), + array( '%s' ), + array( '%d' ) + ); + + return true; + } + + /** + * Return the user data for the given consumer_key. + * + * @param string $consumer_key Consumer key. + * @return array + */ + private function get_user_data_by_consumer_key( $consumer_key ) { + global $wpdb; + + $consumer_key = wc_api_hash( sanitize_text_field( $consumer_key ) ); + $user = $wpdb->get_row( + $wpdb->prepare( + " + SELECT key_id, user_id, permissions, consumer_key, consumer_secret, nonces + FROM {$wpdb->prefix}woocommerce_api_keys + WHERE consumer_key = %s + ", + $consumer_key + ) + ); + + return $user; + } + + /** + * Check that the API keys provided have the proper key-specific permissions to either read or write API resources. + * + * @param string $method Request method. + * @return bool|WP_Error + */ + private function check_permissions( $method ) { + $permissions = $this->user->permissions; + + switch ( $method ) { + case 'HEAD': + case 'GET': + if ( 'read' !== $permissions && 'read_write' !== $permissions ) { + return new WP_Error( 'woocommerce_rest_authentication_error', __( 'The API key provided does not have read permissions.', 'woocommerce' ), array( 'status' => 401 ) ); + } + break; + case 'POST': + case 'PUT': + case 'PATCH': + case 'DELETE': + if ( 'write' !== $permissions && 'read_write' !== $permissions ) { + return new WP_Error( 'woocommerce_rest_authentication_error', __( 'The API key provided does not have write permissions.', 'woocommerce' ), array( 'status' => 401 ) ); + } + break; + case 'OPTIONS': + return true; + + default: + return new WP_Error( 'woocommerce_rest_authentication_error', __( 'Unknown request method.', 'woocommerce' ), array( 'status' => 401 ) ); + } + + return true; + } + + /** + * Updated API Key last access datetime. + */ + private function update_last_access() { + global $wpdb; + + $wpdb->update( + $wpdb->prefix . 'woocommerce_api_keys', + array( 'last_access' => current_time( 'mysql' ) ), + array( 'key_id' => $this->user->key_id ), + array( '%s' ), + array( '%d' ) + ); + } + + /** + * If the consumer_key and consumer_secret $_GET parameters are NOT provided + * and the Basic auth headers are either not present or the consumer secret does not match the consumer + * key provided, then return the correct Basic headers and an error message. + * + * @param WP_REST_Response $response Current response being served. + * @return WP_REST_Response + */ + public function send_unauthorized_headers( $response ) { + if ( is_wp_error( $this->get_error() ) && 'basic_auth' === $this->auth_method ) { + $auth_message = __( 'WooCommerce API. Use a consumer key in the username field and a consumer secret in the password field.', 'woocommerce' ); + $response->header( 'WWW-Authenticate', 'Basic realm="' . $auth_message . '"', true ); + } + + return $response; + } + + /** + * Check for user permissions and register last access. + * + * @param mixed $result Response to replace the requested version with. + * @param WP_REST_Server $server Server instance. + * @param WP_REST_Request $request Request used to generate the response. + * @return mixed + */ + public function check_user_permissions( $result, $server, $request ) { + if ( $this->user ) { + // Check API Key permissions. + $allowed = $this->check_permissions( $request->get_method() ); + if ( is_wp_error( $allowed ) ) { + return $allowed; + } + + // Register last access. + $this->update_last_access(); + } + + return $result; + } +} + +new WC_REST_Authentication(); diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-rest-exception.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-rest-exception.php new file mode 100644 index 0000000..0545b53 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-rest-exception.php @@ -0,0 +1,16 @@ +_cookie = apply_filters( 'woocommerce_cookie', 'wp_woocommerce_session_' . COOKIEHASH ); + $this->_table = $GLOBALS['wpdb']->prefix . 'woocommerce_sessions'; + } + + /** + * Init hooks and session data. + * + * @since 3.3.0 + */ + public function init() { + $this->init_session_cookie(); + + add_action( 'woocommerce_set_cart_cookies', array( $this, 'set_customer_session_cookie' ), 10 ); + add_action( 'shutdown', array( $this, 'save_data' ), 20 ); + add_action( 'wp_logout', array( $this, 'destroy_session' ) ); + + if ( ! is_user_logged_in() ) { + add_filter( 'nonce_user_logged_out', array( $this, 'nonce_user_logged_out' ) ); + } + } + + /** + * Setup cookie and customer ID. + * + * @since 3.6.0 + */ + public function init_session_cookie() { + $cookie = $this->get_session_cookie(); + + if ( $cookie ) { + $this->_customer_id = $cookie[0]; + $this->_session_expiration = $cookie[1]; + $this->_session_expiring = $cookie[2]; + $this->_has_cookie = true; + $this->_data = $this->get_session_data(); + + // If the user logs in, update session. + if ( is_user_logged_in() && strval( get_current_user_id() ) !== $this->_customer_id ) { + $guest_session_id = $this->_customer_id; + $this->_customer_id = strval( get_current_user_id() ); + $this->_dirty = true; + $this->save_data( $guest_session_id ); + $this->set_customer_session_cookie( true ); + } + + // Update session if its close to expiring. + if ( time() > $this->_session_expiring ) { + $this->set_session_expiration(); + $this->update_session_timestamp( $this->_customer_id, $this->_session_expiration ); + } + } else { + $this->set_session_expiration(); + $this->_customer_id = $this->generate_customer_id(); + $this->_data = $this->get_session_data(); + } + } + + /** + * Sets the session cookie on-demand (usually after adding an item to the cart). + * + * Since the cookie name (as of 2.1) is prepended with wp, cache systems like batcache will not cache pages when set. + * + * Warning: Cookies will only be set if this is called before the headers are sent. + * + * @param bool $set Should the session cookie be set. + */ + public function set_customer_session_cookie( $set ) { + if ( $set ) { + $to_hash = $this->_customer_id . '|' . $this->_session_expiration; + $cookie_hash = hash_hmac( 'md5', $to_hash, wp_hash( $to_hash ) ); + $cookie_value = $this->_customer_id . '||' . $this->_session_expiration . '||' . $this->_session_expiring . '||' . $cookie_hash; + $this->_has_cookie = true; + + if ( ! isset( $_COOKIE[ $this->_cookie ] ) || $_COOKIE[ $this->_cookie ] !== $cookie_value ) { + wc_setcookie( $this->_cookie, $cookie_value, $this->_session_expiration, $this->use_secure_cookie(), true ); + } + } + } + + /** + * Should the session cookie be secure? + * + * @since 3.6.0 + * @return bool + */ + protected function use_secure_cookie() { + return apply_filters( 'wc_session_use_secure_cookie', wc_site_is_https() && is_ssl() ); + } + + /** + * Return true if the current user has an active session, i.e. a cookie to retrieve values. + * + * @return bool + */ + public function has_session() { + return isset( $_COOKIE[ $this->_cookie ] ) || $this->_has_cookie || is_user_logged_in(); // @codingStandardsIgnoreLine. + } + + /** + * Set session expiration. + */ + public function set_session_expiration() { + $this->_session_expiring = time() + intval( apply_filters( 'wc_session_expiring', 60 * 60 * 47 ) ); // 47 Hours. + $this->_session_expiration = time() + intval( apply_filters( 'wc_session_expiration', 60 * 60 * 48 ) ); // 48 Hours. + } + + /** + * Generate a unique customer ID for guests, or return user ID if logged in. + * + * Uses Portable PHP password hashing framework to generate a unique cryptographically strong ID. + * + * @return string + */ + public function generate_customer_id() { + $customer_id = ''; + + if ( is_user_logged_in() ) { + $customer_id = strval( get_current_user_id() ); + } + + if ( empty( $customer_id ) ) { + require_once ABSPATH . 'wp-includes/class-phpass.php'; + $hasher = new PasswordHash( 8, false ); + $customer_id = md5( $hasher->get_random_bytes( 32 ) ); + } + + return $customer_id; + } + + /** + * Get the session cookie, if set. Otherwise return false. + * + * Session cookies without a customer ID are invalid. + * + * @return bool|array + */ + public function get_session_cookie() { + $cookie_value = isset( $_COOKIE[ $this->_cookie ] ) ? wp_unslash( $_COOKIE[ $this->_cookie ] ) : false; // @codingStandardsIgnoreLine. + + if ( empty( $cookie_value ) || ! is_string( $cookie_value ) ) { + return false; + } + + list( $customer_id, $session_expiration, $session_expiring, $cookie_hash ) = explode( '||', $cookie_value ); + + if ( empty( $customer_id ) ) { + return false; + } + + // Validate hash. + $to_hash = $customer_id . '|' . $session_expiration; + $hash = hash_hmac( 'md5', $to_hash, wp_hash( $to_hash ) ); + + if ( empty( $cookie_hash ) || ! hash_equals( $hash, $cookie_hash ) ) { + return false; + } + + return array( $customer_id, $session_expiration, $session_expiring, $cookie_hash ); + } + + /** + * Get session data. + * + * @return array + */ + public function get_session_data() { + return $this->has_session() ? (array) $this->get_session( $this->_customer_id, array() ) : array(); + } + + /** + * Gets a cache prefix. This is used in session names so the entire cache can be invalidated with 1 function call. + * + * @return string + */ + private function get_cache_prefix() { + return WC_Cache_Helper::get_cache_prefix( WC_SESSION_CACHE_GROUP ); + } + + /** + * Save data and delete guest session. + * + * @param int $old_session_key session ID before user logs in. + */ + public function save_data( $old_session_key = 0 ) { + // Dirty if something changed - prevents saving nothing new. + if ( $this->_dirty && $this->has_session() ) { + global $wpdb; + + $wpdb->query( + $wpdb->prepare( + "INSERT INTO {$wpdb->prefix}woocommerce_sessions (`session_key`, `session_value`, `session_expiry`) VALUES (%s, %s, %d) + ON DUPLICATE KEY UPDATE `session_value` = VALUES(`session_value`), `session_expiry` = VALUES(`session_expiry`)", + $this->_customer_id, + maybe_serialize( $this->_data ), + $this->_session_expiration + ) + ); + + wp_cache_set( $this->get_cache_prefix() . $this->_customer_id, $this->_data, WC_SESSION_CACHE_GROUP, $this->_session_expiration - time() ); + $this->_dirty = false; + if ( get_current_user_id() != $old_session_key && ! is_object( get_user_by( 'id', $old_session_key ) ) ) { + $this->delete_session( $old_session_key ); + } + } + } + + /** + * Destroy all session data. + */ + public function destroy_session() { + $this->delete_session( $this->_customer_id ); + $this->forget_session(); + } + + /** + * Forget all session data without destroying it. + */ + public function forget_session() { + wc_setcookie( $this->_cookie, '', time() - YEAR_IN_SECONDS, $this->use_secure_cookie(), true ); + + wc_empty_cart(); + + $this->_data = array(); + $this->_dirty = false; + $this->_customer_id = $this->generate_customer_id(); + } + + /** + * When a user is logged out, ensure they have a unique nonce by using the customer/session ID. + * + * @param int $uid User ID. + * @return string + */ + public function nonce_user_logged_out( $uid ) { + return $this->has_session() && $this->_customer_id ? $this->_customer_id : $uid; + } + + /** + * Cleanup session data from the database and clear caches. + */ + public function cleanup_sessions() { + global $wpdb; + + $wpdb->query( $wpdb->prepare( "DELETE FROM $this->_table WHERE session_expiry < %d", time() ) ); // @codingStandardsIgnoreLine. + + if ( class_exists( 'WC_Cache_Helper' ) ) { + WC_Cache_Helper::invalidate_cache_group( WC_SESSION_CACHE_GROUP ); + } + } + + /** + * Returns the session. + * + * @param string $customer_id Custo ID. + * @param mixed $default Default session value. + * @return string|array + */ + public function get_session( $customer_id, $default = false ) { + global $wpdb; + + if ( Constants::is_defined( 'WP_SETUP_CONFIG' ) ) { + return false; + } + + // Try to get it from the cache, it will return false if not present or if object cache not in use. + $value = wp_cache_get( $this->get_cache_prefix() . $customer_id, WC_SESSION_CACHE_GROUP ); + + if ( false === $value ) { + $value = $wpdb->get_var( $wpdb->prepare( "SELECT session_value FROM $this->_table WHERE session_key = %s", $customer_id ) ); // @codingStandardsIgnoreLine. + + if ( is_null( $value ) ) { + $value = $default; + } + + $cache_duration = $this->_session_expiration - time(); + if ( 0 < $cache_duration ) { + wp_cache_add( $this->get_cache_prefix() . $customer_id, $value, WC_SESSION_CACHE_GROUP, $cache_duration ); + } + } + + return maybe_unserialize( $value ); + } + + /** + * Delete the session from the cache and database. + * + * @param int $customer_id Customer ID. + */ + public function delete_session( $customer_id ) { + global $wpdb; + + wp_cache_delete( $this->get_cache_prefix() . $customer_id, WC_SESSION_CACHE_GROUP ); + + $wpdb->delete( + $this->_table, + array( + 'session_key' => $customer_id, + ) + ); + } + + /** + * Update the session expiry timestamp. + * + * @param string $customer_id Customer ID. + * @param int $timestamp Timestamp to expire the cookie. + */ + public function update_session_timestamp( $customer_id, $timestamp ) { + global $wpdb; + + $wpdb->update( + $this->_table, + array( + 'session_expiry' => $timestamp, + ), + array( + 'session_key' => $customer_id, + ), + array( + '%d', + ) + ); + } +} diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-shipping-rate.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-shipping-rate.php new file mode 100644 index 0000000..1248a70 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-shipping-rate.php @@ -0,0 +1,252 @@ + '', + 'method_id' => '', + 'instance_id' => 0, + 'label' => '', + 'cost' => 0, + 'taxes' => array(), + ); + + /** + * Stores meta data for this rate. + * + * @since 2.6.0 + * @var array + */ + protected $meta_data = array(); + + /** + * Constructor. + * + * @param string $id Shipping rate ID. + * @param string $label Shipping rate label. + * @param integer $cost Cost. + * @param array $taxes Taxes applied to shipping rate. + * @param string $method_id Shipping method ID. + * @param int $instance_id Shipping instance ID. + */ + public function __construct( $id = '', $label = '', $cost = 0, $taxes = array(), $method_id = '', $instance_id = 0 ) { + $this->set_id( $id ); + $this->set_label( $label ); + $this->set_cost( $cost ); + $this->set_taxes( $taxes ); + $this->set_method_id( $method_id ); + $this->set_instance_id( $instance_id ); + } + + /** + * Magic methods to support direct access to props. + * + * @since 3.2.0 + * @param string $key Key. + * @return bool + */ + public function __isset( $key ) { + return isset( $this->data[ $key ] ); + } + + /** + * Magic methods to support direct access to props. + * + * @since 3.2.0 + * @param string $key Key. + * @return mixed + */ + public function __get( $key ) { + if ( is_callable( array( $this, "get_{$key}" ) ) ) { + return $this->{"get_{$key}"}(); + } elseif ( isset( $this->data[ $key ] ) ) { + return $this->data[ $key ]; + } else { + return ''; + } + } + + /** + * Magic methods to support direct access to props. + * + * @since 3.2.0 + * @param string $key Key. + * @param mixed $value Value. + */ + public function __set( $key, $value ) { + if ( is_callable( array( $this, "set_{$key}" ) ) ) { + $this->{"set_{$key}"}( $value ); + } else { + $this->data[ $key ] = $value; + } + } + + /** + * Set ID for the rate. This is usually a combination of the method and instance IDs. + * + * @since 3.2.0 + * @param string $id Shipping rate ID. + */ + public function set_id( $id ) { + $this->data['id'] = (string) $id; + } + + /** + * Set shipping method ID the rate belongs to. + * + * @since 3.2.0 + * @param string $method_id Shipping method ID. + */ + public function set_method_id( $method_id ) { + $this->data['method_id'] = (string) $method_id; + } + + /** + * Set instance ID the rate belongs to. + * + * @since 3.2.0 + * @param int $instance_id Instance ID. + */ + public function set_instance_id( $instance_id ) { + $this->data['instance_id'] = absint( $instance_id ); + } + + /** + * Set rate label. + * + * @since 3.2.0 + * @param string $label Shipping rate label. + */ + public function set_label( $label ) { + $this->data['label'] = (string) $label; + } + + /** + * Set rate cost. + * + * @todo 4.0 Prevent negative value being set. #19293 + * @since 3.2.0 + * @param string $cost Shipping rate cost. + */ + public function set_cost( $cost ) { + $this->data['cost'] = $cost; + } + + /** + * Set rate taxes. + * + * @since 3.2.0 + * @param array $taxes List of taxes applied to shipping rate. + */ + public function set_taxes( $taxes ) { + $this->data['taxes'] = ! empty( $taxes ) && is_array( $taxes ) ? $taxes : array(); + } + + /** + * Set ID for the rate. This is usually a combination of the method and instance IDs. + * + * @since 3.2.0 + * @return string + */ + public function get_id() { + return apply_filters( 'woocommerce_shipping_rate_id', $this->data['id'], $this ); + } + + /** + * Set shipping method ID the rate belongs to. + * + * @since 3.2.0 + * @return string + */ + public function get_method_id() { + return apply_filters( 'woocommerce_shipping_rate_method_id', $this->data['method_id'], $this ); + } + + /** + * Set instance ID the rate belongs to. + * + * @since 3.2.0 + * @return int + */ + public function get_instance_id() { + return apply_filters( 'woocommerce_shipping_rate_instance_id', $this->data['instance_id'], $this ); + } + + /** + * Set rate label. + * + * @return string + */ + public function get_label() { + return apply_filters( 'woocommerce_shipping_rate_label', $this->data['label'], $this ); + } + + /** + * Set rate cost. + * + * @since 3.2.0 + * @return string + */ + public function get_cost() { + return apply_filters( 'woocommerce_shipping_rate_cost', $this->data['cost'], $this ); + } + + /** + * Set rate taxes. + * + * @since 3.2.0 + * @return array + */ + public function get_taxes() { + return apply_filters( 'woocommerce_shipping_rate_taxes', $this->data['taxes'], $this ); + } + + /** + * Get shipping tax. + * + * @return array + */ + public function get_shipping_tax() { + return apply_filters( 'woocommerce_get_shipping_tax', count( $this->taxes ) > 0 && ! WC()->customer->get_is_vat_exempt() ? array_sum( $this->taxes ) : 0, $this ); + } + + /** + * Add some meta data for this rate. + * + * @since 2.6.0 + * @param string $key Key. + * @param string $value Value. + */ + public function add_meta_data( $key, $value ) { + $this->meta_data[ wc_clean( $key ) ] = wc_clean( $value ); + } + + /** + * Get all meta data for this rate. + * + * @since 2.6.0 + * @return array + */ + public function get_meta_data() { + return $this->meta_data; + } +} diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-shipping-zone.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-shipping-zone.php new file mode 100644 index 0000000..f092789 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-shipping-zone.php @@ -0,0 +1,462 @@ + '', + 'zone_order' => 0, + 'zone_locations' => array(), + ); + + /** + * Constructor for zones. + * + * @param int|object $zone Zone ID to load from the DB or zone object. + */ + public function __construct( $zone = null ) { + if ( is_numeric( $zone ) && ! empty( $zone ) ) { + $this->set_id( $zone ); + } elseif ( is_object( $zone ) ) { + $this->set_id( $zone->zone_id ); + } elseif ( 0 === $zone || '0' === $zone ) { + $this->set_id( 0 ); + } else { + $this->set_object_read( true ); + } + + $this->data_store = WC_Data_Store::load( 'shipping-zone' ); + if ( false === $this->get_object_read() ) { + $this->data_store->read( $this ); + } + } + + /** + * -------------------------------------------------------------------------- + * Getters + * -------------------------------------------------------------------------- + */ + + /** + * Get zone name. + * + * @param string $context View or edit context. + * @return string + */ + public function get_zone_name( $context = 'view' ) { + return $this->get_prop( 'zone_name', $context ); + } + + /** + * Get zone order. + * + * @param string $context View or edit context. + * @return int + */ + public function get_zone_order( $context = 'view' ) { + return $this->get_prop( 'zone_order', $context ); + } + + /** + * Get zone locations. + * + * @param string $context View or edit context. + * @return array of zone objects + */ + public function get_zone_locations( $context = 'view' ) { + return $this->get_prop( 'zone_locations', $context ); + } + + /** + * Return a text string representing what this zone is for. + * + * @param int $max Max locations to return. + * @param string $context View or edit context. + * @return string + */ + public function get_formatted_location( $max = 10, $context = 'view' ) { + $location_parts = array(); + $all_continents = WC()->countries->get_continents(); + $all_countries = WC()->countries->get_countries(); + $all_states = WC()->countries->get_states(); + $locations = $this->get_zone_locations( $context ); + $continents = array_filter( $locations, array( $this, 'location_is_continent' ) ); + $countries = array_filter( $locations, array( $this, 'location_is_country' ) ); + $states = array_filter( $locations, array( $this, 'location_is_state' ) ); + $postcodes = array_filter( $locations, array( $this, 'location_is_postcode' ) ); + + foreach ( $continents as $location ) { + $location_parts[] = $all_continents[ $location->code ]['name']; + } + + foreach ( $countries as $location ) { + $location_parts[] = $all_countries[ $location->code ]; + } + + foreach ( $states as $location ) { + $location_codes = explode( ':', $location->code ); + $location_parts[] = $all_states[ $location_codes[0] ][ $location_codes[1] ]; + } + + foreach ( $postcodes as $location ) { + $location_parts[] = $location->code; + } + + // Fix display of encoded characters. + $location_parts = array_map( 'html_entity_decode', $location_parts ); + + if ( count( $location_parts ) > $max ) { + $remaining = count( $location_parts ) - $max; + // @codingStandardsIgnoreStart + return sprintf( _n( '%s and %d other region', '%s and %d other regions', $remaining, 'woocommerce' ), implode( ', ', array_splice( $location_parts, 0, $max ) ), $remaining ); + // @codingStandardsIgnoreEnd + } elseif ( ! empty( $location_parts ) ) { + return implode( ', ', $location_parts ); + } else { + return __( 'Everywhere', 'woocommerce' ); + } + } + + /** + * Get shipping methods linked to this zone. + * + * @param bool $enabled_only Only return enabled methods. + * @param string $context Getting shipping methods for what context. Valid values, admin, json. + * @return array of objects + */ + public function get_shipping_methods( $enabled_only = false, $context = 'admin' ) { + if ( null === $this->get_id() ) { + return array(); + } + + $raw_methods = $this->data_store->get_methods( $this->get_id(), $enabled_only ); + $wc_shipping = WC_Shipping::instance(); + $allowed_classes = $wc_shipping->get_shipping_method_class_names(); + $methods = array(); + + foreach ( $raw_methods as $raw_method ) { + if ( in_array( $raw_method->method_id, array_keys( $allowed_classes ), true ) ) { + $class_name = $allowed_classes[ $raw_method->method_id ]; + $instance_id = $raw_method->instance_id; + + // The returned array may contain instances of shipping methods, as well + // as classes. If the "class" is an instance, just use it. If not, + // create an instance. + if ( is_object( $class_name ) ) { + $class_name_of_instance = get_class( $class_name ); + $methods[ $instance_id ] = new $class_name_of_instance( $instance_id ); + } else { + // If the class is not an object, it should be a string. It's better + // to double check, to be sure (a class must be a string, anything) + // else would be useless. + if ( is_string( $class_name ) && class_exists( $class_name ) ) { + $methods[ $instance_id ] = new $class_name( $instance_id ); + } + } + + // Let's make sure that we have an instance before setting its attributes. + if ( is_object( $methods[ $instance_id ] ) ) { + $methods[ $instance_id ]->method_order = absint( $raw_method->method_order ); + $methods[ $instance_id ]->enabled = $raw_method->is_enabled ? 'yes' : 'no'; + $methods[ $instance_id ]->has_settings = $methods[ $instance_id ]->has_settings(); + $methods[ $instance_id ]->settings_html = $methods[ $instance_id ]->supports( 'instance-settings-modal' ) ? $methods[ $instance_id ]->get_admin_options_html() : false; + $methods[ $instance_id ]->method_description = wp_kses_post( wpautop( $methods[ $instance_id ]->method_description ) ); + } + + if ( 'json' === $context ) { + // We don't want the entire object in this context, just the public props. + $methods[ $instance_id ] = (object) get_object_vars( $methods[ $instance_id ] ); + unset( $methods[ $instance_id ]->instance_form_fields, $methods[ $instance_id ]->form_fields ); + } + } + } + + uasort( $methods, 'wc_shipping_zone_method_order_uasort_comparison' ); + + return apply_filters( 'woocommerce_shipping_zone_shipping_methods', $methods, $raw_methods, $allowed_classes, $this ); + } + + /** + * -------------------------------------------------------------------------- + * Setters + * -------------------------------------------------------------------------- + */ + + /** + * Set zone name. + * + * @param string $set Value to set. + */ + public function set_zone_name( $set ) { + $this->set_prop( 'zone_name', wc_clean( $set ) ); + } + + /** + * Set zone order. Value to set. + * + * @param int $set Value to set. + */ + public function set_zone_order( $set ) { + $this->set_prop( 'zone_order', absint( $set ) ); + } + + /** + * Set zone locations. + * + * @since 3.0.0 + * @param array $locations Value to set. + */ + public function set_zone_locations( $locations ) { + if ( 0 !== $this->get_id() ) { + $this->set_prop( 'zone_locations', $locations ); + } + } + + /** + * -------------------------------------------------------------------------- + * Other + * -------------------------------------------------------------------------- + */ + + /** + * Save zone data to the database. + * + * @return int + */ + public function save() { + if ( ! $this->get_zone_name() ) { + $this->set_zone_name( $this->generate_zone_name() ); + } + + if ( ! $this->data_store ) { + return $this->get_id(); + } + + /** + * Trigger action before saving to the DB. Allows you to adjust object props before save. + * + * @param WC_Data $this The object being saved. + * @param WC_Data_Store_WP $data_store THe data store persisting the data. + */ + do_action( 'woocommerce_before_' . $this->object_type . '_object_save', $this, $this->data_store ); + + if ( null !== $this->get_id() ) { + $this->data_store->update( $this ); + } else { + $this->data_store->create( $this ); + } + + /** + * Trigger action after saving to the DB. + * + * @param WC_Data $this The object being saved. + * @param WC_Data_Store_WP $data_store THe data store persisting the data. + */ + do_action( 'woocommerce_after_' . $this->object_type . '_object_save', $this, $this->data_store ); + + return $this->get_id(); + } + + /** + * Generate a zone name based on location. + * + * @return string + */ + protected function generate_zone_name() { + $zone_name = $this->get_formatted_location(); + + if ( empty( $zone_name ) ) { + $zone_name = __( 'Zone', 'woocommerce' ); + } + + return $zone_name; + } + + /** + * Location type detection. + * + * @param object $location Location to check. + * @return boolean + */ + private function location_is_continent( $location ) { + return 'continent' === $location->type; + } + + /** + * Location type detection. + * + * @param object $location Location to check. + * @return boolean + */ + private function location_is_country( $location ) { + return 'country' === $location->type; + } + + /** + * Location type detection. + * + * @param object $location Location to check. + * @return boolean + */ + private function location_is_state( $location ) { + return 'state' === $location->type; + } + + /** + * Location type detection. + * + * @param object $location Location to check. + * @return boolean + */ + private function location_is_postcode( $location ) { + return 'postcode' === $location->type; + } + + /** + * Is passed location type valid? + * + * @param string $type Type to check. + * @return boolean + */ + public function is_valid_location_type( $type ) { + return in_array( $type, apply_filters( 'woocommerce_valid_location_types', array( 'postcode', 'state', 'country', 'continent' ) ), true ); + } + + /** + * Add location (state or postcode) to a zone. + * + * @param string $code Location code. + * @param string $type state or postcode. + */ + public function add_location( $code, $type ) { + if ( 0 !== $this->get_id() && $this->is_valid_location_type( $type ) ) { + if ( 'postcode' === $type ) { + $code = trim( strtoupper( str_replace( chr( 226 ) . chr( 128 ) . chr( 166 ), '...', $code ) ) ); // No normalization - postcodes are matched against both normal and formatted versions to support wildcards. + } + $location = array( + 'code' => wc_clean( $code ), + 'type' => wc_clean( $type ), + ); + $zone_locations = $this->get_prop( 'zone_locations', 'edit' ); + $zone_locations[] = (object) $location; + $this->set_prop( 'zone_locations', $zone_locations ); + } + } + + + /** + * Clear all locations for this zone. + * + * @param array|string $types of location to clear. + */ + public function clear_locations( $types = array( 'postcode', 'state', 'country', 'continent' ) ) { + if ( ! is_array( $types ) ) { + $types = array( $types ); + } + $zone_locations = $this->get_prop( 'zone_locations', 'edit' ); + foreach ( $zone_locations as $key => $values ) { + if ( in_array( $values->type, $types, true ) ) { + unset( $zone_locations[ $key ] ); + } + } + $zone_locations = array_values( $zone_locations ); // reindex. + $this->set_prop( 'zone_locations', $zone_locations ); + } + + /** + * Set locations. + * + * @param array $locations Array of locations. + */ + public function set_locations( $locations = array() ) { + $this->clear_locations(); + foreach ( $locations as $location ) { + $this->add_location( $location['code'], $location['type'] ); + } + } + + /** + * Add a shipping method to this zone. + * + * @param string $type shipping method type. + * @return int new instance_id, 0 on failure + */ + public function add_shipping_method( $type ) { + if ( null === $this->get_id() ) { + $this->save(); + } + + $instance_id = 0; + $wc_shipping = WC_Shipping::instance(); + $allowed_classes = $wc_shipping->get_shipping_method_class_names(); + $count = $this->data_store->get_method_count( $this->get_id() ); + + if ( in_array( $type, array_keys( $allowed_classes ), true ) ) { + $instance_id = $this->data_store->add_method( $this->get_id(), $type, $count + 1 ); + } + + if ( $instance_id ) { + do_action( 'woocommerce_shipping_zone_method_added', $instance_id, $type, $this->get_id() ); + } + + WC_Cache_Helper::get_transient_version( 'shipping', true ); + + return $instance_id; + } + + /** + * Delete a shipping method from a zone. + * + * @param int $instance_id Shipping method instance ID. + * @return True on success, false on failure + */ + public function delete_shipping_method( $instance_id ) { + if ( null === $this->get_id() ) { + return false; + } + + // Get method details. + $method = $this->data_store->get_method( $instance_id ); + + if ( $method ) { + $this->data_store->delete_method( $instance_id ); + do_action( 'woocommerce_shipping_zone_method_deleted', $instance_id, $method->method_id, $this->get_id() ); + } + + WC_Cache_Helper::get_transient_version( 'shipping', true ); + + return true; + } +} diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-shipping-zones.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-shipping-zones.php new file mode 100644 index 0000000..4acff8b --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-shipping-zones.php @@ -0,0 +1,142 @@ +get_zones(); + $zones = array(); + + foreach ( $raw_zones as $raw_zone ) { + $zone = new WC_Shipping_Zone( $raw_zone ); + $zones[ $zone->get_id() ] = $zone->get_data(); + $zones[ $zone->get_id() ]['zone_id'] = $zone->get_id(); + $zones[ $zone->get_id() ]['formatted_zone_location'] = $zone->get_formatted_location(); + $zones[ $zone->get_id() ]['shipping_methods'] = $zone->get_shipping_methods( false, $context ); + } + + return $zones; + } + + /** + * Get shipping zone using it's ID + * + * @since 2.6.0 + * @param int $zone_id Zone ID. + * @return WC_Shipping_Zone|bool + */ + public static function get_zone( $zone_id ) { + return self::get_zone_by( 'zone_id', $zone_id ); + } + + /** + * Get shipping zone by an ID. + * + * @since 2.6.0 + * @param string $by Get by 'zone_id' or 'instance_id'. + * @param int $id ID. + * @return WC_Shipping_Zone|bool + */ + public static function get_zone_by( $by = 'zone_id', $id = 0 ) { + $zone_id = false; + + switch ( $by ) { + case 'zone_id': + $zone_id = $id; + break; + case 'instance_id': + $data_store = WC_Data_Store::load( 'shipping-zone' ); + $zone_id = $data_store->get_zone_id_by_instance_id( $id ); + break; + } + + if ( false !== $zone_id ) { + try { + return new WC_Shipping_Zone( $zone_id ); + } catch ( Exception $e ) { + return false; + } + } + + return false; + } + + /** + * Get shipping zone using it's ID. + * + * @since 2.6.0 + * @param int $instance_id Instance ID. + * @return bool|WC_Shipping_Method + */ + public static function get_shipping_method( $instance_id ) { + $data_store = WC_Data_Store::load( 'shipping-zone' ); + $raw_shipping_method = $data_store->get_method( $instance_id ); + $wc_shipping = WC_Shipping::instance(); + $allowed_classes = $wc_shipping->get_shipping_method_class_names(); + + if ( ! empty( $raw_shipping_method ) && in_array( $raw_shipping_method->method_id, array_keys( $allowed_classes ), true ) ) { + $class_name = $allowed_classes[ $raw_shipping_method->method_id ]; + if ( is_object( $class_name ) ) { + $class_name = get_class( $class_name ); + } + return new $class_name( $raw_shipping_method->instance_id ); + } + return false; + } + + /** + * Delete a zone using it's ID + * + * @param int $zone_id Zone ID. + * @since 2.6.0 + */ + public static function delete_zone( $zone_id ) { + $zone = new WC_Shipping_Zone( $zone_id ); + $zone->delete(); + } + + /** + * Find a matching zone for a given package. + * + * @since 2.6.0 + * @uses wc_make_numeric_postcode() + * @param array $package Shipping package. + * @return WC_Shipping_Zone + */ + public static function get_zone_matching_package( $package ) { + $country = strtoupper( wc_clean( $package['destination']['country'] ) ); + $state = strtoupper( wc_clean( $package['destination']['state'] ) ); + $postcode = wc_normalize_postcode( wc_clean( $package['destination']['postcode'] ) ); + $cache_key = WC_Cache_Helper::get_cache_prefix( 'shipping_zones' ) . 'wc_shipping_zone_' . md5( sprintf( '%s+%s+%s', $country, $state, $postcode ) ); + $matching_zone_id = wp_cache_get( $cache_key, 'shipping_zones' ); + + if ( false === $matching_zone_id ) { + $data_store = WC_Data_Store::load( 'shipping-zone' ); + $matching_zone_id = $data_store->get_zone_id_from_package( $package ); + wp_cache_set( $cache_key, $matching_zone_id, 'shipping_zones' ); + } + + return new WC_Shipping_Zone( $matching_zone_id ? $matching_zone_id : 0 ); + } +} diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-shipping.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-shipping.php new file mode 100644 index 0000000..6dcc53a --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-shipping.php @@ -0,0 +1,404 @@ +cart->get_shipping_total(); + } + if ( 'shipping_taxes' === $name ) { + return WC()->cart->get_shipping_taxes(); + } + } + + /** + * Initialize shipping. + */ + public function __construct() { + $this->enabled = wc_shipping_enabled(); + + if ( $this->enabled ) { + $this->init(); + } + } + + /** + * Initialize shipping. + */ + public function init() { + do_action( 'woocommerce_shipping_init' ); + } + + /** + * Shipping methods register themselves by returning their main class name through the woocommerce_shipping_methods filter. + * + * @return array + */ + public function get_shipping_method_class_names() { + // Unique Method ID => Method Class name. + $shipping_methods = array( + 'flat_rate' => 'WC_Shipping_Flat_Rate', + 'free_shipping' => 'WC_Shipping_Free_Shipping', + 'local_pickup' => 'WC_Shipping_Local_Pickup', + ); + + // For backwards compatibility with 2.5.x we load any ENABLED legacy shipping methods here. + $maybe_load_legacy_methods = array( 'flat_rate', 'free_shipping', 'international_delivery', 'local_delivery', 'local_pickup' ); + + foreach ( $maybe_load_legacy_methods as $method ) { + $options = get_option( 'woocommerce_' . $method . '_settings' ); + if ( $options && isset( $options['enabled'] ) && 'yes' === $options['enabled'] ) { + $shipping_methods[ 'legacy_' . $method ] = 'WC_Shipping_Legacy_' . $method; + } + } + + return apply_filters( 'woocommerce_shipping_methods', $shipping_methods ); + } + + /** + * Loads all shipping methods which are hooked in. + * If a $package is passed, some methods may add themselves conditionally and zones will be used. + * + * @param array $package Package information. + * @return WC_Shipping_Method[] + */ + public function load_shipping_methods( $package = array() ) { + if ( ! empty( $package ) ) { + $debug_mode = 'yes' === get_option( 'woocommerce_shipping_debug_mode', 'no' ); + $shipping_zone = WC_Shipping_Zones::get_zone_matching_package( $package ); + $this->shipping_methods = $shipping_zone->get_shipping_methods( true ); + + // translators: %s: shipping zone name. + $matched_zone_notice = sprintf( __( 'Customer matched zone "%s"', 'woocommerce' ), $shipping_zone->get_zone_name() ); + + // Debug output. + if ( $debug_mode && ! Constants::is_defined( 'WOOCOMMERCE_CHECKOUT' ) && ! Constants::is_defined( 'WC_DOING_AJAX' ) && ! wc_has_notice( $matched_zone_notice ) ) { + wc_add_notice( $matched_zone_notice ); + } + } else { + $this->shipping_methods = array(); + } + + // For the settings in the backend, and for non-shipping zone methods, we still need to load any registered classes here. + foreach ( $this->get_shipping_method_class_names() as $method_id => $method_class ) { + $this->register_shipping_method( $method_class ); + } + + // Methods can register themselves manually through this hook if necessary. + do_action( 'woocommerce_load_shipping_methods', $package ); + + // Return loaded methods. + return $this->get_shipping_methods(); + } + + /** + * Register a shipping method. + * + * @param object|string $method Either the name of the method's class, or an instance of the method's class. + * + * @return bool|void + */ + public function register_shipping_method( $method ) { + if ( ! is_object( $method ) ) { + if ( ! class_exists( $method ) ) { + return false; + } + $method = new $method(); + } + if ( is_null( $this->shipping_methods ) ) { + $this->shipping_methods = array(); + } + $this->shipping_methods[ $method->id ] = $method; + } + + /** + * Unregister shipping methods. + */ + public function unregister_shipping_methods() { + $this->shipping_methods = null; + } + + /** + * Returns all registered shipping methods for usage. + * + * @return WC_Shipping_Method[] + */ + public function get_shipping_methods() { + if ( is_null( $this->shipping_methods ) ) { + $this->load_shipping_methods(); + } + return $this->shipping_methods; + } + + /** + * Get an array of shipping classes. + * + * @return array + */ + public function get_shipping_classes() { + if ( empty( $this->shipping_classes ) ) { + $classes = get_terms( + 'product_shipping_class', + array( + 'hide_empty' => '0', + 'orderby' => 'name', + ) + ); + $this->shipping_classes = ! is_wp_error( $classes ) ? $classes : array(); + } + return apply_filters( 'woocommerce_get_shipping_classes', $this->shipping_classes ); + } + + /** + * Calculate shipping for (multiple) packages of cart items. + * + * @param array $packages multi-dimensional array of cart items to calc shipping for. + * @return array Array of calculated packages. + */ + public function calculate_shipping( $packages = array() ) { + $this->packages = array(); + + if ( ! $this->enabled || empty( $packages ) ) { + return array(); + } + + // Calculate costs for passed packages. + foreach ( $packages as $package_key => $package ) { + $this->packages[ $package_key ] = $this->calculate_shipping_for_package( $package, $package_key ); + } + + /** + * Allow packages to be reorganized after calculating the shipping. + * + * This filter can be used to apply some extra manipulation after the shipping costs are calculated for the packages + * but before WooCommerce does anything with them. A good example of usage is to merge the shipping methods for multiple + * packages for marketplaces. + * + * @since 2.6.0 + * + * @param array $packages The array of packages after shipping costs are calculated. + */ + $this->packages = array_filter( (array) apply_filters( 'woocommerce_shipping_packages', $this->packages ) ); + + return $this->packages; + } + + /** + * See if package is shippable. + * + * Packages are shippable until proven otherwise e.g. after getting a shipping country. + * + * @param array $package Package of cart items. + * @return bool + */ + public function is_package_shippable( $package ) { + // Packages are shippable until proven otherwise. + if ( empty( $package['destination']['country'] ) ) { + return true; + } + + $allowed = array_keys( WC()->countries->get_shipping_countries() ); + return in_array( $package['destination']['country'], $allowed, true ); + } + + /** + * Calculate shipping rates for a package, + * + * Calculates each shipping methods cost. Rates are stored in the session based on the package hash to avoid re-calculation every page load. + * + * @param array $package Package of cart items. + * @param int $package_key Index of the package being calculated. Used to cache multiple package rates. + * + * @return array|bool + */ + public function calculate_shipping_for_package( $package = array(), $package_key = 0 ) { + // If shipping is disabled or the package is invalid, return false. + if ( ! $this->enabled || empty( $package ) ) { + return false; + } + + $package['rates'] = array(); + + // If the package is not shippable, e.g. trying to ship to an invalid country, do not calculate rates. + if ( $this->is_package_shippable( $package ) ) { + // Check if we need to recalculate shipping for this package. + $package_to_hash = $package; + + // Remove data objects so hashes are consistent. + foreach ( $package_to_hash['contents'] as $item_id => $item ) { + unset( $package_to_hash['contents'][ $item_id ]['data'] ); + } + + // Get rates stored in the WC session data for this package. + $wc_session_key = 'shipping_for_package_' . $package_key; + $stored_rates = WC()->session->get( $wc_session_key ); + + // Calculate the hash for this package so we can tell if it's changed since last calculation. + $package_hash = 'wc_ship_' . md5( wp_json_encode( $package_to_hash ) . WC_Cache_Helper::get_transient_version( 'shipping' ) ); + + if ( ! is_array( $stored_rates ) || $package_hash !== $stored_rates['package_hash'] || 'yes' === get_option( 'woocommerce_shipping_debug_mode', 'no' ) ) { + foreach ( $this->load_shipping_methods( $package ) as $shipping_method ) { + if ( ! $shipping_method->supports( 'shipping-zones' ) || $shipping_method->get_instance_id() ) { + /** + * Fires before getting shipping rates for a package. + * + * @since 4.3.0 + * @param array $package Package of cart items. + * @param WC_Shipping_Method $shipping_method Shipping method instance. + */ + do_action( 'woocommerce_before_get_rates_for_package', $package, $shipping_method ); + + // Use + instead of array_merge to maintain numeric keys. + $package['rates'] = $package['rates'] + $shipping_method->get_rates_for_package( $package ); + + /** + * Fires after getting shipping rates for a package. + * + * @since 4.3.0 + * @param array $package Package of cart items. + * @param WC_Shipping_Method $shipping_method Shipping method instance. + */ + do_action( 'woocommerce_after_get_rates_for_package', $package, $shipping_method ); + } + } + + // Filter the calculated rates. + $package['rates'] = apply_filters( 'woocommerce_package_rates', $package['rates'], $package ); + + // Store in session to avoid recalculation. + WC()->session->set( + $wc_session_key, + array( + 'package_hash' => $package_hash, + 'rates' => $package['rates'], + ) + ); + } else { + $package['rates'] = $stored_rates['rates']; + } + } + return $package; + } + + /** + * Get packages. + * + * @return array + */ + public function get_packages() { + return $this->packages; + } + + /** + * Reset shipping. + * + * Reset the totals for shipping as a whole. + */ + public function reset_shipping() { + unset( WC()->session->chosen_shipping_methods ); + $this->packages = array(); + } + + /** + * Deprecated + * + * @deprecated 2.6.0 Was previously used to determine sort order of methods, but this is now controlled by zones and thus unused. + */ + public function sort_shipping_methods() { + wc_deprecated_function( 'sort_shipping_methods', '2.6' ); + return $this->shipping_methods; + } +} diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-shortcodes.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-shortcodes.php new file mode 100644 index 0000000..b8eaa08 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-shortcodes.php @@ -0,0 +1,699 @@ + __CLASS__ . '::product', + 'product_page' => __CLASS__ . '::product_page', + 'product_category' => __CLASS__ . '::product_category', + 'product_categories' => __CLASS__ . '::product_categories', + 'add_to_cart' => __CLASS__ . '::product_add_to_cart', + 'add_to_cart_url' => __CLASS__ . '::product_add_to_cart_url', + 'products' => __CLASS__ . '::products', + 'recent_products' => __CLASS__ . '::recent_products', + 'sale_products' => __CLASS__ . '::sale_products', + 'best_selling_products' => __CLASS__ . '::best_selling_products', + 'top_rated_products' => __CLASS__ . '::top_rated_products', + 'featured_products' => __CLASS__ . '::featured_products', + 'product_attribute' => __CLASS__ . '::product_attribute', + 'related_products' => __CLASS__ . '::related_products', + 'shop_messages' => __CLASS__ . '::shop_messages', + 'woocommerce_order_tracking' => __CLASS__ . '::order_tracking', + 'woocommerce_cart' => __CLASS__ . '::cart', + 'woocommerce_checkout' => __CLASS__ . '::checkout', + 'woocommerce_my_account' => __CLASS__ . '::my_account', + ); + + foreach ( $shortcodes as $shortcode => $function ) { + add_shortcode( apply_filters( "{$shortcode}_shortcode_tag", $shortcode ), $function ); + } + + // Alias for pre 2.1 compatibility. + add_shortcode( 'woocommerce_messages', __CLASS__ . '::shop_messages' ); + } + + /** + * Shortcode Wrapper. + * + * @param string[] $function Callback function. + * @param array $atts Attributes. Default to empty array. + * @param array $wrapper Customer wrapper data. + * + * @return string + */ + public static function shortcode_wrapper( + $function, + $atts = array(), + $wrapper = array( + 'class' => 'woocommerce', + 'before' => null, + 'after' => null, + ) + ) { + ob_start(); + + // @codingStandardsIgnoreStart + echo empty( $wrapper['before'] ) ? '
' : $wrapper['after']; + // @codingStandardsIgnoreEnd + + return ob_get_clean(); + } + + /** + * Cart page shortcode. + * + * @return string + */ + public static function cart() { + return is_null( WC()->cart ) ? '' : self::shortcode_wrapper( array( 'WC_Shortcode_Cart', 'output' ) ); + } + + /** + * Checkout page shortcode. + * + * @param array $atts Attributes. + * @return string + */ + public static function checkout( $atts ) { + return self::shortcode_wrapper( array( 'WC_Shortcode_Checkout', 'output' ), $atts ); + } + + /** + * Order tracking page shortcode. + * + * @param array $atts Attributes. + * @return string + */ + public static function order_tracking( $atts ) { + return self::shortcode_wrapper( array( 'WC_Shortcode_Order_Tracking', 'output' ), $atts ); + } + + /** + * My account page shortcode. + * + * @param array $atts Attributes. + * @return string + */ + public static function my_account( $atts ) { + return self::shortcode_wrapper( array( 'WC_Shortcode_My_Account', 'output' ), $atts ); + } + + /** + * List products in a category shortcode. + * + * @param array $atts Attributes. + * @return string + */ + public static function product_category( $atts ) { + if ( empty( $atts['category'] ) ) { + return ''; + } + + $atts = array_merge( + array( + 'limit' => '12', + 'columns' => '4', + 'orderby' => 'menu_order title', + 'order' => 'ASC', + 'category' => '', + 'cat_operator' => 'IN', + ), + (array) $atts + ); + + $shortcode = new WC_Shortcode_Products( $atts, 'product_category' ); + + return $shortcode->get_content(); + } + + /** + * List all (or limited) product categories. + * + * @param array $atts Attributes. + * @return string + */ + public static function product_categories( $atts ) { + if ( isset( $atts['number'] ) ) { + $atts['limit'] = $atts['number']; + } + + $atts = shortcode_atts( + array( + 'limit' => '-1', + 'orderby' => 'name', + 'order' => 'ASC', + 'columns' => '4', + 'hide_empty' => 1, + 'parent' => '', + 'ids' => '', + ), + $atts, + 'product_categories' + ); + + $ids = array_filter( array_map( 'trim', explode( ',', $atts['ids'] ) ) ); + $hide_empty = ( true === $atts['hide_empty'] || 'true' === $atts['hide_empty'] || 1 === $atts['hide_empty'] || '1' === $atts['hide_empty'] ) ? 1 : 0; + + // Get terms and workaround WP bug with parents/pad counts. + $args = array( + 'orderby' => $atts['orderby'], + 'order' => $atts['order'], + 'hide_empty' => $hide_empty, + 'include' => $ids, + 'pad_counts' => true, + 'child_of' => $atts['parent'], + ); + + $product_categories = apply_filters( + 'woocommerce_product_categories', + get_terms( 'product_cat', $args ) + ); + + if ( '' !== $atts['parent'] ) { + $product_categories = wp_list_filter( + $product_categories, + array( + 'parent' => $atts['parent'], + ) + ); + } + + if ( $hide_empty ) { + foreach ( $product_categories as $key => $category ) { + if ( 0 === $category->count ) { + unset( $product_categories[ $key ] ); + } + } + } + + $atts['limit'] = '-1' === $atts['limit'] ? null : intval( $atts['limit'] ); + if ( $atts['limit'] ) { + $product_categories = array_slice( $product_categories, 0, $atts['limit'] ); + } + + $columns = absint( $atts['columns'] ); + + wc_set_loop_prop( 'columns', $columns ); + wc_set_loop_prop( 'is_shortcode', true ); + + ob_start(); + + if ( $product_categories ) { + woocommerce_product_loop_start(); + + foreach ( $product_categories as $category ) { + wc_get_template( + 'content-product_cat.php', + array( + 'category' => $category, + ) + ); + } + + woocommerce_product_loop_end(); + } + + wc_reset_loop(); + + return '
'; + } + + /** + * Recent Products shortcode. + * + * @param array $atts Attributes. + * @return string + */ + public static function recent_products( $atts ) { + $atts = array_merge( + array( + 'limit' => '12', + 'columns' => '4', + 'orderby' => 'date', + 'order' => 'DESC', + 'category' => '', + 'cat_operator' => 'IN', + ), + (array) $atts + ); + + $shortcode = new WC_Shortcode_Products( $atts, 'recent_products' ); + + return $shortcode->get_content(); + } + + /** + * List multiple products shortcode. + * + * @param array $atts Attributes. + * @return string + */ + public static function products( $atts ) { + $atts = (array) $atts; + $type = 'products'; + + // Allow list product based on specific cases. + if ( isset( $atts['on_sale'] ) && wc_string_to_bool( $atts['on_sale'] ) ) { + $type = 'sale_products'; + } elseif ( isset( $atts['best_selling'] ) && wc_string_to_bool( $atts['best_selling'] ) ) { + $type = 'best_selling_products'; + } elseif ( isset( $atts['top_rated'] ) && wc_string_to_bool( $atts['top_rated'] ) ) { + $type = 'top_rated_products'; + } + + $shortcode = new WC_Shortcode_Products( $atts, $type ); + + return $shortcode->get_content(); + } + + /** + * Display a single product. + * + * @param array $atts Attributes. + * @return string + */ + public static function product( $atts ) { + if ( empty( $atts ) ) { + return ''; + } + + $atts['skus'] = isset( $atts['sku'] ) ? $atts['sku'] : ''; + $atts['ids'] = isset( $atts['id'] ) ? $atts['id'] : ''; + $atts['limit'] = '1'; + $shortcode = new WC_Shortcode_Products( (array) $atts, 'product' ); + + return $shortcode->get_content(); + } + + /** + * Display a single product price + cart button. + * + * @param array $atts Attributes. + * @return string + */ + public static function product_add_to_cart( $atts ) { + global $post; + + if ( empty( $atts ) ) { + return ''; + } + + $atts = shortcode_atts( + array( + 'id' => '', + 'class' => '', + 'quantity' => '1', + 'sku' => '', + 'style' => 'border:4px solid #ccc; padding: 12px;', + 'show_price' => 'true', + ), + $atts, + 'product_add_to_cart' + ); + + if ( ! empty( $atts['id'] ) ) { + $product_data = get_post( $atts['id'] ); + } elseif ( ! empty( $atts['sku'] ) ) { + $product_id = wc_get_product_id_by_sku( $atts['sku'] ); + $product_data = get_post( $product_id ); + } else { + return ''; + } + + $product = is_object( $product_data ) && in_array( $product_data->post_type, array( 'product', 'product_variation' ), true ) ? wc_setup_product_data( $product_data ) : false; + + if ( ! $product ) { + return ''; + } + + ob_start(); + + echo '
'; + + if ( wc_string_to_bool( $atts['show_price'] ) ) { + // @codingStandardsIgnoreStart + echo $product->get_price_html(); + // @codingStandardsIgnoreEnd + } + + woocommerce_template_loop_add_to_cart( + array( + 'quantity' => $atts['quantity'], + ) + ); + + echo '
'; + + // Restore Product global in case this is shown inside a product post. + wc_setup_product_data( $post ); + + return ob_get_clean(); + } + + /** + * Get the add to cart URL for a product. + * + * @param array $atts Attributes. + * @return string + */ + public static function product_add_to_cart_url( $atts ) { + if ( empty( $atts ) ) { + return ''; + } + + if ( isset( $atts['id'] ) ) { + $product_data = get_post( $atts['id'] ); + } elseif ( isset( $atts['sku'] ) ) { + $product_id = wc_get_product_id_by_sku( $atts['sku'] ); + $product_data = get_post( $product_id ); + } else { + return ''; + } + + $product = is_object( $product_data ) && in_array( $product_data->post_type, array( 'product', 'product_variation' ), true ) ? wc_setup_product_data( $product_data ) : false; + + if ( ! $product ) { + return ''; + } + + $_product = wc_get_product( $product_data ); + + return esc_url( $_product->add_to_cart_url() ); + } + + /** + * List all products on sale. + * + * @param array $atts Attributes. + * @return string + */ + public static function sale_products( $atts ) { + $atts = array_merge( + array( + 'limit' => '12', + 'columns' => '4', + 'orderby' => 'title', + 'order' => 'ASC', + 'category' => '', + 'cat_operator' => 'IN', + ), + (array) $atts + ); + + $shortcode = new WC_Shortcode_Products( $atts, 'sale_products' ); + + return $shortcode->get_content(); + } + + /** + * List best selling products on sale. + * + * @param array $atts Attributes. + * @return string + */ + public static function best_selling_products( $atts ) { + $atts = array_merge( + array( + 'limit' => '12', + 'columns' => '4', + 'category' => '', + 'cat_operator' => 'IN', + ), + (array) $atts + ); + + $shortcode = new WC_Shortcode_Products( $atts, 'best_selling_products' ); + + return $shortcode->get_content(); + } + + /** + * List top rated products on sale. + * + * @param array $atts Attributes. + * @return string + */ + public static function top_rated_products( $atts ) { + $atts = array_merge( + array( + 'limit' => '12', + 'columns' => '4', + 'orderby' => 'title', + 'order' => 'ASC', + 'category' => '', + 'cat_operator' => 'IN', + ), + (array) $atts + ); + + $shortcode = new WC_Shortcode_Products( $atts, 'top_rated_products' ); + + return $shortcode->get_content(); + } + + /** + * Output featured products. + * + * @param array $atts Attributes. + * @return string + */ + public static function featured_products( $atts ) { + $atts = array_merge( + array( + 'limit' => '12', + 'columns' => '4', + 'orderby' => 'date', + 'order' => 'DESC', + 'category' => '', + 'cat_operator' => 'IN', + ), + (array) $atts + ); + + $atts['visibility'] = 'featured'; + + $shortcode = new WC_Shortcode_Products( $atts, 'featured_products' ); + + return $shortcode->get_content(); + } + + /** + * Show a single product page. + * + * @param array $atts Attributes. + * @return string + */ + public static function product_page( $atts ) { + if ( empty( $atts ) ) { + return ''; + } + + if ( ! isset( $atts['id'] ) && ! isset( $atts['sku'] ) ) { + return ''; + } + + $args = array( + 'posts_per_page' => 1, + 'post_type' => 'product', + 'post_status' => ( ! empty( $atts['status'] ) ) ? $atts['status'] : 'publish', + 'ignore_sticky_posts' => 1, + 'no_found_rows' => 1, + ); + + if ( isset( $atts['sku'] ) ) { + $args['meta_query'][] = array( + 'key' => '_sku', + 'value' => sanitize_text_field( $atts['sku'] ), + 'compare' => '=', + ); + + $args['post_type'] = array( 'product', 'product_variation' ); + } + + if ( isset( $atts['id'] ) ) { + $args['p'] = absint( $atts['id'] ); + } + + // Don't render titles if desired. + if ( isset( $atts['show_title'] ) && ! $atts['show_title'] ) { + remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_title', 5 ); + } + + // Change form action to avoid redirect. + add_filter( 'woocommerce_add_to_cart_form_action', '__return_empty_string' ); + + $single_product = new WP_Query( $args ); + + $preselected_id = '0'; + + // Check if sku is a variation. + if ( isset( $atts['sku'] ) && $single_product->have_posts() && 'product_variation' === $single_product->post->post_type ) { + + $variation = wc_get_product_object( 'variation', $single_product->post->ID ); + $attributes = $variation->get_attributes(); + + // Set preselected id to be used by JS to provide context. + $preselected_id = $single_product->post->ID; + + // Get the parent product object. + $args = array( + 'posts_per_page' => 1, + 'post_type' => 'product', + 'post_status' => 'publish', + 'ignore_sticky_posts' => 1, + 'no_found_rows' => 1, + 'p' => $single_product->post->post_parent, + ); + + $single_product = new WP_Query( $args ); + ?> + + is_single = true; + + ob_start(); + + global $wp_query; + + // Backup query object so following loops think this is a product page. + $previous_wp_query = $wp_query; + // @codingStandardsIgnoreStart + $wp_query = $single_product; + // @codingStandardsIgnoreEnd + + wp_enqueue_script( 'wc-single-product' ); + + while ( $single_product->have_posts() ) { + $single_product->the_post() + ?> +
+ ' . ob_get_clean() . ''; + } + + /** + * Show messages. + * + * @return string + */ + public static function shop_messages() { + if ( ! function_exists( 'wc_print_notices' ) ) { + return ''; + } + return '
'; + } + + /** + * Order by rating. + * + * @deprecated 3.2.0 Use WC_Shortcode_Products::order_by_rating_post_clauses(). + * @param array $args Query args. + * @return array + */ + public static function order_by_rating_post_clauses( $args ) { + return WC_Shortcode_Products::order_by_rating_post_clauses( $args ); + } + + /** + * List products with an attribute shortcode. + * Example [product_attribute attribute="color" filter="black"]. + * + * @param array $atts Attributes. + * @return string + */ + public static function product_attribute( $atts ) { + $atts = array_merge( + array( + 'limit' => '12', + 'columns' => '4', + 'orderby' => 'title', + 'order' => 'ASC', + 'attribute' => '', + 'terms' => '', + ), + (array) $atts + ); + + if ( empty( $atts['attribute'] ) ) { + return ''; + } + + $shortcode = new WC_Shortcode_Products( $atts, 'product_attribute' ); + + return $shortcode->get_content(); + } + + /** + * List related products. + * + * @param array $atts Attributes. + * @return string + */ + public static function related_products( $atts ) { + if ( isset( $atts['per_page'] ) ) { + $atts['limit'] = $atts['per_page']; + } + + // @codingStandardsIgnoreStart + $atts = shortcode_atts( array( + 'limit' => '4', + 'columns' => '4', + 'orderby' => 'rand', + ), $atts, 'related_products' ); + // @codingStandardsIgnoreEnd + + ob_start(); + + // Rename arg. + $atts['posts_per_page'] = absint( $atts['limit'] ); + + woocommerce_related_products( $atts ); + + return ob_get_clean(); + } +} diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-structured-data.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-structured-data.php new file mode 100644 index 0000000..070bea6 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-structured-data.php @@ -0,0 +1,538 @@ +_data ) ) { + unset( $this->_data ); + } + + $this->_data[] = $data; + + return true; + } + + /** + * Gets data. + * + * @return array + */ + public function get_data() { + return $this->_data; + } + + /** + * Structures and returns data. + * + * List of types available by default for specific request: + * + * 'product', + * 'review', + * 'breadcrumblist', + * 'website', + * 'order', + * + * @param array $types Structured data types. + * @return array + */ + public function get_structured_data( $types ) { + $data = array(); + + // Put together the values of same type of structured data. + foreach ( $this->get_data() as $value ) { + $data[ strtolower( $value['@type'] ) ][] = $value; + } + + // Wrap the multiple values of each type inside a graph... Then add context to each type. + foreach ( $data as $type => $value ) { + $data[ $type ] = count( $value ) > 1 ? array( '@graph' => $value ) : $value[0]; + $data[ $type ] = apply_filters( 'woocommerce_structured_data_context', array( '@context' => 'https://schema.org/' ), $data, $type, $value ) + $data[ $type ]; + } + + // If requested types, pick them up... Finally change the associative array to an indexed one. + $data = $types ? array_values( array_intersect_key( $data, array_flip( $types ) ) ) : array_values( $data ); + + if ( ! empty( $data ) ) { + if ( 1 < count( $data ) ) { + $data = apply_filters( 'woocommerce_structured_data_context', array( '@context' => 'https://schema.org/' ), $data, '', '' ) + array( '@graph' => $data ); + } else { + $data = $data[0]; + } + } + + return $data; + } + + /** + * Get data types for pages. + * + * @return array + */ + protected function get_data_type_for_page() { + $types = array(); + $types[] = is_shop() || is_product_category() || is_product() ? 'product' : ''; + $types[] = is_shop() && is_front_page() ? 'website' : ''; + $types[] = is_product() ? 'review' : ''; + $types[] = 'breadcrumblist'; + $types[] = 'order'; + + return array_filter( apply_filters( 'woocommerce_structured_data_type_for_page', $types ) ); + } + + /** + * Makes sure email structured data only outputs on non-plain text versions. + * + * @param WP_Order $order Order data. + * @param bool $sent_to_admin Send to admin (default: false). + * @param bool $plain_text Plain text email (default: false). + */ + public function output_email_structured_data( $order, $sent_to_admin = false, $plain_text = false ) { + if ( $plain_text ) { + return; + } + echo '
'; + } + + /** + * Sanitizes, encodes and outputs structured data. + * + * Hooked into `wp_footer` action hook. + * Hooked into `woocommerce_email_order_details` action hook. + */ + public function output_structured_data() { + $types = $this->get_data_type_for_page(); + $data = $this->get_structured_data( $types ); + + if ( $data ) { + echo ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + } + } + + /* + |-------------------------------------------------------------------------- + | Generators + |-------------------------------------------------------------------------- + | + | Methods for generating specific structured data types: + | + | - Product + | - Review + | - BreadcrumbList + | - WebSite + | - Order + | + | The generated data is stored into `$this->_data`. + | See the methods above for handling `$this->_data`. + | + */ + + /** + * Generates Product structured data. + * + * Hooked into `woocommerce_single_product_summary` action hook. + * + * @param WC_Product $product Product data (default: null). + */ + public function generate_product_data( $product = null ) { + if ( ! is_object( $product ) ) { + global $product; + } + + if ( ! is_a( $product, 'WC_Product' ) ) { + return; + } + + $shop_name = get_bloginfo( 'name' ); + $shop_url = home_url(); + $currency = get_woocommerce_currency(); + $permalink = get_permalink( $product->get_id() ); + $image = wp_get_attachment_url( $product->get_image_id() ); + + $markup = array( + '@type' => 'Product', + '@id' => $permalink . '#product', // Append '#product' to differentiate between this @id and the @id generated for the Breadcrumblist. + 'name' => $product->get_name(), + 'url' => $permalink, + 'description' => wp_strip_all_tags( do_shortcode( $product->get_short_description() ? $product->get_short_description() : $product->get_description() ) ), + ); + + if ( $image ) { + $markup['image'] = $image; + } + + // Declare SKU or fallback to ID. + if ( $product->get_sku() ) { + $markup['sku'] = $product->get_sku(); + } else { + $markup['sku'] = $product->get_id(); + } + + if ( '' !== $product->get_price() ) { + // Assume prices will be valid until the end of next year, unless on sale and there is an end date. + $price_valid_until = gmdate( 'Y-12-31', time() + YEAR_IN_SECONDS ); + + if ( $product->is_type( 'variable' ) ) { + $lowest = $product->get_variation_price( 'min', false ); + $highest = $product->get_variation_price( 'max', false ); + + if ( $lowest === $highest ) { + $markup_offer = array( + '@type' => 'Offer', + 'price' => wc_format_decimal( $lowest, wc_get_price_decimals() ), + 'priceValidUntil' => $price_valid_until, + 'priceSpecification' => array( + 'price' => wc_format_decimal( $lowest, wc_get_price_decimals() ), + 'priceCurrency' => $currency, + 'valueAddedTaxIncluded' => wc_prices_include_tax() ? 'true' : 'false', + ), + ); + } else { + $markup_offer = array( + '@type' => 'AggregateOffer', + 'lowPrice' => wc_format_decimal( $lowest, wc_get_price_decimals() ), + 'highPrice' => wc_format_decimal( $highest, wc_get_price_decimals() ), + 'offerCount' => count( $product->get_children() ), + ); + } + } else { + if ( $product->is_on_sale() && $product->get_date_on_sale_to() ) { + $price_valid_until = gmdate( 'Y-m-d', $product->get_date_on_sale_to()->getTimestamp() ); + } + $markup_offer = array( + '@type' => 'Offer', + 'price' => wc_format_decimal( $product->get_price(), wc_get_price_decimals() ), + 'priceValidUntil' => $price_valid_until, + 'priceSpecification' => array( + 'price' => wc_format_decimal( $product->get_price(), wc_get_price_decimals() ), + 'priceCurrency' => $currency, + 'valueAddedTaxIncluded' => wc_prices_include_tax() ? 'true' : 'false', + ), + ); + } + + $markup_offer += array( + 'priceCurrency' => $currency, + 'availability' => 'http://schema.org/' . ( $product->is_in_stock() ? 'InStock' : 'OutOfStock' ), + 'url' => $permalink, + 'seller' => array( + '@type' => 'Organization', + 'name' => $shop_name, + 'url' => $shop_url, + ), + ); + + $markup['offers'] = array( apply_filters( 'woocommerce_structured_data_product_offer', $markup_offer, $product ) ); + } + + if ( $product->get_rating_count() && wc_review_ratings_enabled() ) { + $markup['aggregateRating'] = array( + '@type' => 'AggregateRating', + 'ratingValue' => $product->get_average_rating(), + 'reviewCount' => $product->get_review_count(), + ); + + // Markup 5 most recent rating/review. + $comments = get_comments( + array( + 'number' => 5, + 'post_id' => $product->get_id(), + 'status' => 'approve', + 'post_status' => 'publish', + 'post_type' => 'product', + 'parent' => 0, + 'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query + array( + 'key' => 'rating', + 'type' => 'NUMERIC', + 'compare' => '>', + 'value' => 0, + ), + ), + ) + ); + + if ( $comments ) { + $markup['review'] = array(); + foreach ( $comments as $comment ) { + $markup['review'][] = array( + '@type' => 'Review', + 'reviewRating' => array( + '@type' => 'Rating', + 'bestRating' => '5', + 'ratingValue' => get_comment_meta( $comment->comment_ID, 'rating', true ), + 'worstRating' => '1', + ), + 'author' => array( + '@type' => 'Person', + 'name' => get_comment_author( $comment ), + ), + 'reviewBody' => get_comment_text( $comment ), + 'datePublished' => get_comment_date( 'c', $comment ), + ); + } + } + } + + // Check we have required data. + if ( empty( $markup['aggregateRating'] ) && empty( $markup['offers'] ) && empty( $markup['review'] ) ) { + return; + } + + $this->set_data( apply_filters( 'woocommerce_structured_data_product', $markup, $product ) ); + } + + /** + * Generates Review structured data. + * + * Hooked into `woocommerce_review_meta` action hook. + * + * @param WP_Comment $comment Comment data. + */ + public function generate_review_data( $comment ) { + $markup = array(); + $markup['@type'] = 'Review'; + $markup['@id'] = get_comment_link( $comment->comment_ID ); + $markup['datePublished'] = get_comment_date( 'c', $comment->comment_ID ); + $markup['description'] = get_comment_text( $comment->comment_ID ); + $markup['itemReviewed'] = array( + '@type' => 'Product', + 'name' => get_the_title( $comment->comment_post_ID ), + ); + + // Skip replies unless they have a rating. + $rating = get_comment_meta( $comment->comment_ID, 'rating', true ); + + if ( $rating ) { + $markup['reviewRating'] = array( + '@type' => 'Rating', + 'bestRating' => '5', + 'ratingValue' => $rating, + 'worstRating' => '1', + ); + } elseif ( $comment->comment_parent ) { + return; + } + + $markup['author'] = array( + '@type' => 'Person', + 'name' => get_comment_author( $comment->comment_ID ), + ); + + $this->set_data( apply_filters( 'woocommerce_structured_data_review', $markup, $comment ) ); + } + + /** + * Generates BreadcrumbList structured data. + * + * Hooked into `woocommerce_breadcrumb` action hook. + * + * @param WC_Breadcrumb $breadcrumbs Breadcrumb data. + */ + public function generate_breadcrumblist_data( $breadcrumbs ) { + $crumbs = $breadcrumbs->get_breadcrumb(); + + if ( empty( $crumbs ) || ! is_array( $crumbs ) ) { + return; + } + + $markup = array(); + $markup['@type'] = 'BreadcrumbList'; + $markup['itemListElement'] = array(); + + foreach ( $crumbs as $key => $crumb ) { + $markup['itemListElement'][ $key ] = array( + '@type' => 'ListItem', + 'position' => $key + 1, + 'item' => array( + 'name' => $crumb[0], + ), + ); + + if ( ! empty( $crumb[1] ) ) { + $markup['itemListElement'][ $key ]['item'] += array( '@id' => $crumb[1] ); + } elseif ( isset( $_SERVER['HTTP_HOST'], $_SERVER['REQUEST_URI'] ) ) { + $current_url = set_url_scheme( 'http://' . wp_unslash( $_SERVER['HTTP_HOST'] ) . wp_unslash( $_SERVER['REQUEST_URI'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + + $markup['itemListElement'][ $key ]['item'] += array( '@id' => $current_url ); + } + } + + $this->set_data( apply_filters( 'woocommerce_structured_data_breadcrumblist', $markup, $breadcrumbs ) ); + } + + /** + * Generates WebSite structured data. + * + * Hooked into `woocommerce_before_main_content` action hook. + */ + public function generate_website_data() { + $markup = array(); + $markup['@type'] = 'WebSite'; + $markup['name'] = get_bloginfo( 'name' ); + $markup['url'] = home_url(); + $markup['potentialAction'] = array( + '@type' => 'SearchAction', + 'target' => home_url( '?s={search_term_string}&post_type=product' ), + 'query-input' => 'required name=search_term_string', + ); + + $this->set_data( apply_filters( 'woocommerce_structured_data_website', $markup ) ); + } + + /** + * Generates Order structured data. + * + * Hooked into `woocommerce_email_order_details` action hook. + * + * @param WP_Order $order Order data. + * @param bool $sent_to_admin Send to admin (default: false). + * @param bool $plain_text Plain text email (default: false). + */ + public function generate_order_data( $order, $sent_to_admin = false, $plain_text = false ) { + if ( $plain_text || ! is_a( $order, 'WC_Order' ) ) { + return; + } + + $shop_name = get_bloginfo( 'name' ); + $shop_url = home_url(); + $order_url = $sent_to_admin ? $order->get_edit_order_url() : $order->get_view_order_url(); + $order_statuses = array( + 'pending' => 'https://schema.org/OrderPaymentDue', + 'processing' => 'https://schema.org/OrderProcessing', + 'on-hold' => 'https://schema.org/OrderProblem', + 'completed' => 'https://schema.org/OrderDelivered', + 'cancelled' => 'https://schema.org/OrderCancelled', + 'refunded' => 'https://schema.org/OrderReturned', + 'failed' => 'https://schema.org/OrderProblem', + ); + + $markup_offers = array(); + foreach ( $order->get_items() as $item ) { + if ( ! apply_filters( 'woocommerce_order_item_visible', true, $item ) ) { + continue; + } + + $product = $item->get_product(); + $product_exists = is_object( $product ); + $is_visible = $product_exists && $product->is_visible(); + + $markup_offers[] = array( + '@type' => 'Offer', + 'price' => $order->get_line_subtotal( $item ), + 'priceCurrency' => $order->get_currency(), + 'priceSpecification' => array( + 'price' => $order->get_line_subtotal( $item ), + 'priceCurrency' => $order->get_currency(), + 'eligibleQuantity' => array( + '@type' => 'QuantitativeValue', + 'value' => apply_filters( 'woocommerce_email_order_item_quantity', $item->get_quantity(), $item ), + ), + ), + 'itemOffered' => array( + '@type' => 'Product', + 'name' => apply_filters( 'woocommerce_order_item_name', $item->get_name(), $item, $is_visible ), + 'sku' => $product_exists ? $product->get_sku() : '', + 'image' => $product_exists ? wp_get_attachment_image_url( $product->get_image_id() ) : '', + 'url' => $is_visible ? get_permalink( $product->get_id() ) : get_home_url(), + ), + 'seller' => array( + '@type' => 'Organization', + 'name' => $shop_name, + 'url' => $shop_url, + ), + ); + } + + $markup = array(); + $markup['@type'] = 'Order'; + $markup['url'] = $order_url; + $markup['orderStatus'] = isset( $order_statuses[ $order->get_status() ] ) ? $order_statuses[ $order->get_status() ] : ''; + $markup['orderNumber'] = $order->get_order_number(); + $markup['orderDate'] = $order->get_date_created()->format( 'c' ); + $markup['acceptedOffer'] = $markup_offers; + $markup['discount'] = $order->get_total_discount(); + $markup['discountCurrency'] = $order->get_currency(); + $markup['price'] = $order->get_total(); + $markup['priceCurrency'] = $order->get_currency(); + $markup['priceSpecification'] = array( + 'price' => $order->get_total(), + 'priceCurrency' => $order->get_currency(), + 'valueAddedTaxIncluded' => 'true', + ); + $markup['billingAddress'] = array( + '@type' => 'PostalAddress', + 'name' => $order->get_formatted_billing_full_name(), + 'streetAddress' => $order->get_billing_address_1(), + 'postalCode' => $order->get_billing_postcode(), + 'addressLocality' => $order->get_billing_city(), + 'addressRegion' => $order->get_billing_state(), + 'addressCountry' => $order->get_billing_country(), + 'email' => $order->get_billing_email(), + 'telephone' => $order->get_billing_phone(), + ); + $markup['customer'] = array( + '@type' => 'Person', + 'name' => $order->get_formatted_billing_full_name(), + ); + $markup['merchant'] = array( + '@type' => 'Organization', + 'name' => $shop_name, + 'url' => $shop_url, + ); + $markup['potentialAction'] = array( + '@type' => 'ViewAction', + 'name' => 'View Order', + 'url' => $order_url, + 'target' => $order_url, + ); + + $this->set_data( apply_filters( 'woocommerce_structured_data_order', $markup, $sent_to_admin, $order ), true ); + } +} diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-tax.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-tax.php new file mode 100644 index 0000000..f80a7d8 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-tax.php @@ -0,0 +1,1226 @@ + $rate ) { + $taxes[ $key ] = 0; + + if ( 'yes' === $rate['compound'] ) { + $compound_rates[ $key ] = $rate['rate']; + } else { + $regular_rates[ $key ] = $rate['rate']; + } + } + + $compound_rates = array_reverse( $compound_rates, true ); // Working backwards. + + $non_compound_price = $price; + + foreach ( $compound_rates as $key => $compound_rate ) { + $tax_amount = apply_filters( 'woocommerce_price_inc_tax_amount', $non_compound_price - ( $non_compound_price / ( 1 + ( $compound_rate / 100 ) ) ), $key, $rates[ $key ], $price ); + $taxes[ $key ] += $tax_amount; + $non_compound_price = $non_compound_price - $tax_amount; + } + + // Regular taxes. + $regular_tax_rate = 1 + ( array_sum( $regular_rates ) / 100 ); + + foreach ( $regular_rates as $key => $regular_rate ) { + $the_rate = ( $regular_rate / 100 ) / $regular_tax_rate; + $net_price = $price - ( $the_rate * $non_compound_price ); + $tax_amount = apply_filters( 'woocommerce_price_inc_tax_amount', $price - $net_price, $key, $rates[ $key ], $price ); + $taxes[ $key ] += $tax_amount; + } + + /** + * Round all taxes to precision (4DP) before passing them back. Note, this is not the same rounding + * as in the cart calculation class which, depending on settings, will round to 2DP when calculating + * final totals. Also unlike that class, this rounds .5 up for all cases. + */ + $taxes = array_map( array( __CLASS__, 'round' ), $taxes ); + + return $taxes; + } + + /** + * Calc tax from exclusive price. + * + * @param float $price Price to calculate tax for. + * @param array $rates Array of tax rates. + * @return array + */ + public static function calc_exclusive_tax( $price, $rates ) { + $taxes = array(); + + if ( ! empty( $rates ) ) { + foreach ( $rates as $key => $rate ) { + if ( 'yes' === $rate['compound'] ) { + continue; + } + + $tax_amount = $price * ( $rate['rate'] / 100 ); + $tax_amount = apply_filters( 'woocommerce_price_ex_tax_amount', $tax_amount, $key, $rate, $price ); // ADVANCED: Allow third parties to modify this rate. + + if ( ! isset( $taxes[ $key ] ) ) { + $taxes[ $key ] = $tax_amount; + } else { + $taxes[ $key ] += $tax_amount; + } + } + + $pre_compound_total = array_sum( $taxes ); + + // Compound taxes. + foreach ( $rates as $key => $rate ) { + if ( 'no' === $rate['compound'] ) { + continue; + } + $the_price_inc_tax = $price + ( $pre_compound_total ); + $tax_amount = $the_price_inc_tax * ( $rate['rate'] / 100 ); + $tax_amount = apply_filters( 'woocommerce_price_ex_tax_amount', $tax_amount, $key, $rate, $price, $the_price_inc_tax, $pre_compound_total ); // ADVANCED: Allow third parties to modify this rate. + + if ( ! isset( $taxes[ $key ] ) ) { + $taxes[ $key ] = $tax_amount; + } else { + $taxes[ $key ] += $tax_amount; + } + + $pre_compound_total = array_sum( $taxes ); + } + } + + /** + * Round all taxes to precision (4DP) before passing them back. Note, this is not the same rounding + * as in the cart calculation class which, depending on settings, will round to 2DP when calculating + * final totals. Also unlike that class, this rounds .5 up for all cases. + */ + $taxes = array_map( array( __CLASS__, 'round' ), $taxes ); + + return $taxes; + } + + /** + * Searches for all matching country/state/postcode tax rates. + * + * @param array $args Args that determine the rate to find. + * @return array + */ + public static function find_rates( $args = array() ) { + $args = wp_parse_args( + $args, + array( + 'country' => '', + 'state' => '', + 'city' => '', + 'postcode' => '', + 'tax_class' => '', + ) + ); + + $country = $args['country']; + $state = $args['state']; + $city = $args['city']; + $postcode = wc_normalize_postcode( wc_clean( $args['postcode'] ) ); + $tax_class = $args['tax_class']; + + if ( ! $country ) { + return array(); + } + + $cache_key = WC_Cache_Helper::get_cache_prefix( 'taxes' ) . 'wc_tax_rates_' . md5( sprintf( '%s+%s+%s+%s+%s', $country, $state, $city, $postcode, $tax_class ) ); + $matched_tax_rates = wp_cache_get( $cache_key, 'taxes' ); + + if ( false === $matched_tax_rates ) { + $matched_tax_rates = self::get_matched_tax_rates( $country, $state, $postcode, $city, $tax_class ); + wp_cache_set( $cache_key, $matched_tax_rates, 'taxes' ); + } + + return apply_filters( 'woocommerce_find_rates', $matched_tax_rates, $args ); + } + + /** + * Searches for all matching country/state/postcode tax rates. + * + * @param array $args Args that determine the rate to find. + * @return array + */ + public static function find_shipping_rates( $args = array() ) { + $rates = self::find_rates( $args ); + $shipping_rates = array(); + + if ( is_array( $rates ) ) { + foreach ( $rates as $key => $rate ) { + if ( 'yes' === $rate['shipping'] ) { + $shipping_rates[ $key ] = $rate; + } + } + } + + return $shipping_rates; + } + + /** + * Does the sort comparison. Compares (in this order): + * - Priority + * - Country + * - State + * - Number of postcodes + * - Number of cities + * - ID + * + * @param object $rate1 First rate to compare. + * @param object $rate2 Second rate to compare. + * @return int + */ + private static function sort_rates_callback( $rate1, $rate2 ) { + if ( $rate1->tax_rate_priority !== $rate2->tax_rate_priority ) { + return $rate1->tax_rate_priority < $rate2->tax_rate_priority ? -1 : 1; // ASC. + } + + if ( $rate1->tax_rate_country !== $rate2->tax_rate_country ) { + if ( '' === $rate1->tax_rate_country ) { + return 1; + } + if ( '' === $rate2->tax_rate_country ) { + return -1; + } + return strcmp( $rate1->tax_rate_country, $rate2->tax_rate_country ) > 0 ? 1 : -1; + } + + if ( $rate1->tax_rate_state !== $rate2->tax_rate_state ) { + if ( '' === $rate1->tax_rate_state ) { + return 1; + } + if ( '' === $rate2->tax_rate_state ) { + return -1; + } + return strcmp( $rate1->tax_rate_state, $rate2->tax_rate_state ) > 0 ? 1 : -1; + } + + if ( isset( $rate1->postcode_count, $rate2->postcode_count ) && $rate1->postcode_count !== $rate2->postcode_count ) { + return $rate1->postcode_count < $rate2->postcode_count ? 1 : -1; + } + + if ( isset( $rate1->city_count, $rate2->city_count ) && $rate1->city_count !== $rate2->city_count ) { + return $rate1->city_count < $rate2->city_count ? 1 : -1; + } + + return $rate1->tax_rate_id < $rate2->tax_rate_id ? -1 : 1; + } + + /** + * Logical sort order for tax rates based on the following in order of priority. + * + * @param array $rates Rates to be sorted. + * @return array + */ + private static function sort_rates( $rates ) { + uasort( $rates, __CLASS__ . '::sort_rates_callback' ); + $i = 0; + foreach ( $rates as $key => $rate ) { + $rates[ $key ]->tax_rate_order = $i++; + } + return $rates; + } + + /** + * Loop through a set of tax rates and get the matching rates (1 per priority). + * + * @param string $country Country code to match against. + * @param string $state State code to match against. + * @param string $postcode Postcode to match against. + * @param string $city City to match against. + * @param string $tax_class Tax class to match against. + * @return array + */ + private static function get_matched_tax_rates( $country, $state, $postcode, $city, $tax_class ) { + global $wpdb; + + // Query criteria - these will be ANDed. + $criteria = array(); + $criteria[] = $wpdb->prepare( "tax_rate_country IN ( %s, '' )", strtoupper( $country ) ); + $criteria[] = $wpdb->prepare( "tax_rate_state IN ( %s, '' )", strtoupper( $state ) ); + $criteria[] = $wpdb->prepare( 'tax_rate_class = %s', sanitize_title( $tax_class ) ); + + // Pre-query postcode ranges for PHP based matching. + $postcode_search = wc_get_wildcard_postcodes( $postcode, $country ); + $postcode_ranges = $wpdb->get_results( "SELECT tax_rate_id, location_code FROM {$wpdb->prefix}woocommerce_tax_rate_locations WHERE location_type = 'postcode' AND location_code LIKE '%...%';" ); + + if ( $postcode_ranges ) { + $matches = wc_postcode_location_matcher( $postcode, $postcode_ranges, 'tax_rate_id', 'location_code', $country ); + if ( ! empty( $matches ) ) { + foreach ( $matches as $matched_postcodes ) { + $postcode_search = array_merge( $postcode_search, $matched_postcodes ); + } + } + } + + $postcode_search = array_unique( $postcode_search ); + + /** + * Location matching criteria - ORed + * Needs to match: + * - rates with no postcodes and cities + * - rates with a matching postcode and city + * - rates with matching postcode, no city + * - rates with matching city, no postcode + */ + $locations_criteria = array(); + $locations_criteria[] = 'locations.location_type IS NULL'; + $locations_criteria[] = " + locations.location_type = 'postcode' AND locations.location_code IN ('" . implode( "','", array_map( 'esc_sql', $postcode_search ) ) . "') + AND ( + ( locations2.location_type = 'city' AND locations2.location_code = '" . esc_sql( strtoupper( $city ) ) . "' ) + OR NOT EXISTS ( + SELECT sub.tax_rate_id FROM {$wpdb->prefix}woocommerce_tax_rate_locations as sub + WHERE sub.location_type = 'city' + AND sub.tax_rate_id = tax_rates.tax_rate_id + ) + ) + "; + $locations_criteria[] = " + locations.location_type = 'city' AND locations.location_code = '" . esc_sql( strtoupper( $city ) ) . "' + AND NOT EXISTS ( + SELECT sub.tax_rate_id FROM {$wpdb->prefix}woocommerce_tax_rate_locations as sub + WHERE sub.location_type = 'postcode' + AND sub.tax_rate_id = tax_rates.tax_rate_id + ) + "; + + $criteria[] = '( ( ' . implode( ' ) OR ( ', $locations_criteria ) . ' ) )'; + + $criteria_string = implode( ' AND ', $criteria ); + + // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared + $found_rates = $wpdb->get_results( + " + SELECT tax_rates.*, COUNT( locations.location_id ) as postcode_count, COUNT( locations2.location_id ) as city_count + FROM {$wpdb->prefix}woocommerce_tax_rates as tax_rates + LEFT OUTER JOIN {$wpdb->prefix}woocommerce_tax_rate_locations as locations ON tax_rates.tax_rate_id = locations.tax_rate_id + LEFT OUTER JOIN {$wpdb->prefix}woocommerce_tax_rate_locations as locations2 ON tax_rates.tax_rate_id = locations2.tax_rate_id + WHERE 1=1 AND {$criteria_string} + GROUP BY tax_rates.tax_rate_id + ORDER BY tax_rates.tax_rate_priority + " + ); + // phpcs:enable + + $found_rates = self::sort_rates( $found_rates ); + $matched_tax_rates = array(); + $found_priority = array(); + + foreach ( $found_rates as $found_rate ) { + if ( in_array( $found_rate->tax_rate_priority, $found_priority, true ) ) { + continue; + } + + $matched_tax_rates[ $found_rate->tax_rate_id ] = array( + 'rate' => (float) $found_rate->tax_rate, + 'label' => $found_rate->tax_rate_name, + 'shipping' => $found_rate->tax_rate_shipping ? 'yes' : 'no', + 'compound' => $found_rate->tax_rate_compound ? 'yes' : 'no', + ); + + $found_priority[] = $found_rate->tax_rate_priority; + } + + return apply_filters( 'woocommerce_matched_tax_rates', $matched_tax_rates, $country, $state, $postcode, $city, $tax_class ); + } + + /** + * Get the customer tax location based on their status and the current page. + * + * Used by get_rates(), get_shipping_rates(). + * + * @param string $tax_class string Optional, passed to the filter for advanced tax setups. + * @param object $customer Override the customer object to get their location. + * @return array + */ + public static function get_tax_location( $tax_class = '', $customer = null ) { + $location = array(); + + if ( is_null( $customer ) && WC()->customer ) { + $customer = WC()->customer; + } + + if ( ! empty( $customer ) ) { + $location = $customer->get_taxable_address(); + } elseif ( wc_prices_include_tax() || 'base' === get_option( 'woocommerce_default_customer_address' ) || 'base' === get_option( 'woocommerce_tax_based_on' ) ) { + $location = array( + WC()->countries->get_base_country(), + WC()->countries->get_base_state(), + WC()->countries->get_base_postcode(), + WC()->countries->get_base_city(), + ); + } + + return apply_filters( 'woocommerce_get_tax_location', $location, $tax_class, $customer ); + } + + /** + * Get's an array of matching rates for a tax class. + * + * @param string $tax_class Tax class to get rates for. + * @param object $customer Override the customer object to get their location. + * @return array + */ + public static function get_rates( $tax_class = '', $customer = null ) { + $tax_class = sanitize_title( $tax_class ); + $location = self::get_tax_location( $tax_class, $customer ); + $matched_tax_rates = array(); + + if ( count( $location ) === 4 ) { + list( $country, $state, $postcode, $city ) = $location; + + $matched_tax_rates = self::find_rates( + array( + 'country' => $country, + 'state' => $state, + 'postcode' => $postcode, + 'city' => $city, + 'tax_class' => $tax_class, + ) + ); + } + + return apply_filters( 'woocommerce_matched_rates', $matched_tax_rates, $tax_class, $customer ); + } + + /** + * Get's an array of matching rates for the shop's base country. + * + * @param string $tax_class Tax Class. + * @return array + */ + public static function get_base_tax_rates( $tax_class = '' ) { + return apply_filters( + 'woocommerce_base_tax_rates', + self::find_rates( + array( + 'country' => WC()->countries->get_base_country(), + 'state' => WC()->countries->get_base_state(), + 'postcode' => WC()->countries->get_base_postcode(), + 'city' => WC()->countries->get_base_city(), + 'tax_class' => $tax_class, + ) + ), + $tax_class + ); + } + + /** + * Alias for get_base_tax_rates(). + * + * @deprecated 2.3 + * @param string $tax_class Tax Class. + * @return array + */ + public static function get_shop_base_rate( $tax_class = '' ) { + return self::get_base_tax_rates( $tax_class ); + } + + /** + * Gets an array of matching shipping tax rates for a given class. + * + * @param string $tax_class Tax class to get rates for. + * @param object $customer Override the customer object to get their location. + * @return mixed + */ + public static function get_shipping_tax_rates( $tax_class = null, $customer = null ) { + // See if we have an explicitly set shipping tax class. + $shipping_tax_class = get_option( 'woocommerce_shipping_tax_class' ); + + if ( 'inherit' !== $shipping_tax_class ) { + $tax_class = $shipping_tax_class; + } + + $location = self::get_tax_location( $tax_class, $customer ); + $matched_tax_rates = array(); + + if ( 4 === count( $location ) ) { + list( $country, $state, $postcode, $city ) = $location; + + if ( ! is_null( $tax_class ) ) { + // This will be per item shipping. + $matched_tax_rates = self::find_shipping_rates( + array( + 'country' => $country, + 'state' => $state, + 'postcode' => $postcode, + 'city' => $city, + 'tax_class' => $tax_class, + ) + ); + + } elseif ( WC()->cart->get_cart() ) { + + // This will be per order shipping - loop through the order and find the highest tax class rate. + $cart_tax_classes = WC()->cart->get_cart_item_tax_classes_for_shipping(); + + // No tax classes = no taxable items. + if ( empty( $cart_tax_classes ) ) { + return array(); + } + + // If multiple classes are found, use the first one found unless a standard rate item is found. This will be the first listed in the 'additional tax class' section. + if ( count( $cart_tax_classes ) > 1 && ! in_array( '', $cart_tax_classes, true ) ) { + $tax_classes = self::get_tax_class_slugs(); + + foreach ( $tax_classes as $tax_class ) { + if ( in_array( $tax_class, $cart_tax_classes, true ) ) { + $matched_tax_rates = self::find_shipping_rates( + array( + 'country' => $country, + 'state' => $state, + 'postcode' => $postcode, + 'city' => $city, + 'tax_class' => $tax_class, + ) + ); + break; + } + } + } elseif ( 1 === count( $cart_tax_classes ) ) { + // If a single tax class is found, use it. + $matched_tax_rates = self::find_shipping_rates( + array( + 'country' => $country, + 'state' => $state, + 'postcode' => $postcode, + 'city' => $city, + 'tax_class' => $cart_tax_classes[0], + ) + ); + } + } + + // Get standard rate if no taxes were found. + if ( ! count( $matched_tax_rates ) ) { + $matched_tax_rates = self::find_shipping_rates( + array( + 'country' => $country, + 'state' => $state, + 'postcode' => $postcode, + 'city' => $city, + ) + ); + } + } + + return $matched_tax_rates; + } + + /** + * Return true/false depending on if a rate is a compound rate. + * + * @param mixed $key_or_rate Tax rate ID, or the db row itself in object format. + * @return bool + */ + public static function is_compound( $key_or_rate ) { + global $wpdb; + + if ( is_object( $key_or_rate ) ) { + $key = $key_or_rate->tax_rate_id; + $compound = $key_or_rate->tax_rate_compound; + } else { + $key = $key_or_rate; + $compound = (bool) $wpdb->get_var( $wpdb->prepare( "SELECT tax_rate_compound FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %s", $key ) ); + } + + return (bool) apply_filters( 'woocommerce_rate_compound', $compound, $key ); + } + + /** + * Return a given rates label. + * + * @param mixed $key_or_rate Tax rate ID, or the db row itself in object format. + * @return string + */ + public static function get_rate_label( $key_or_rate ) { + global $wpdb; + + if ( is_object( $key_or_rate ) ) { + $key = $key_or_rate->tax_rate_id; + $rate_name = $key_or_rate->tax_rate_name; + } else { + $key = $key_or_rate; + $rate_name = $wpdb->get_var( $wpdb->prepare( "SELECT tax_rate_name FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %s", $key ) ); + } + + if ( ! $rate_name ) { + $rate_name = WC()->countries->tax_or_vat(); + } + + return apply_filters( 'woocommerce_rate_label', $rate_name, $key ); + } + + /** + * Return a given rates percent. + * + * @param mixed $key_or_rate Tax rate ID, or the db row itself in object format. + * @return string + */ + public static function get_rate_percent( $key_or_rate ) { + $rate_percent_value = self::get_rate_percent_value( $key_or_rate ); + $tax_rate_id = is_object( $key_or_rate ) ? $key_or_rate->tax_rate_id : $key_or_rate; + return apply_filters( 'woocommerce_rate_percent', $rate_percent_value . '%', $tax_rate_id ); + } + + /** + * Return a given rates percent. + * + * @param mixed $key_or_rate Tax rate ID, or the db row itself in object format. + * @return float + */ + public static function get_rate_percent_value( $key_or_rate ) { + global $wpdb; + + if ( is_object( $key_or_rate ) ) { + $tax_rate = $key_or_rate->tax_rate; + } else { + $key = $key_or_rate; + $tax_rate = $wpdb->get_var( $wpdb->prepare( "SELECT tax_rate FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %s", $key ) ); + } + + return floatval( $tax_rate ); + } + + + /** + * Get a rates code. Code is made up of COUNTRY-STATE-NAME-Priority. E.g GB-VAT-1, US-AL-TAX-1. + * + * @param mixed $key_or_rate Tax rate ID, or the db row itself in object format. + * @return string + */ + public static function get_rate_code( $key_or_rate ) { + global $wpdb; + + if ( is_object( $key_or_rate ) ) { + $key = $key_or_rate->tax_rate_id; + $rate = $key_or_rate; + } else { + $key = $key_or_rate; + $rate = $wpdb->get_row( $wpdb->prepare( "SELECT tax_rate_country, tax_rate_state, tax_rate_name, tax_rate_priority FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %s", $key ) ); + } + + $code_string = ''; + + if ( null !== $rate ) { + $code = array(); + $code[] = $rate->tax_rate_country; + $code[] = $rate->tax_rate_state; + $code[] = $rate->tax_rate_name ? $rate->tax_rate_name : 'TAX'; + $code[] = absint( $rate->tax_rate_priority ); + $code_string = strtoupper( implode( '-', array_filter( $code ) ) ); + } + + return apply_filters( 'woocommerce_rate_code', $code_string, $key ); + } + + /** + * Sums a set of taxes to form a single total. Values are pre-rounded to precision from 3.6.0. + * + * @param array $taxes Array of taxes. + * @return float + */ + public static function get_tax_total( $taxes ) { + return array_sum( $taxes ); + } + + /** + * Gets all tax rate classes from the database. + * + * @since 3.7.0 + * @return array Array of tax class objects consisting of tax_rate_class_id, name, and slug. + */ + protected static function get_tax_rate_classes() { + global $wpdb; + + $cache_key = 'tax-rate-classes'; + $tax_rate_classes = wp_cache_get( $cache_key, 'taxes' ); + + if ( ! is_array( $tax_rate_classes ) ) { + $tax_rate_classes = $wpdb->get_results( + " + SELECT * FROM {$wpdb->wc_tax_rate_classes} ORDER BY name; + " + ); + wp_cache_set( $cache_key, $tax_rate_classes, 'taxes' ); + } + + return $tax_rate_classes; + } + + /** + * Get store tax class names. + * + * @return array Array of class names ("Reduced rate", "Zero rate", etc). + */ + public static function get_tax_classes() { + return wp_list_pluck( self::get_tax_rate_classes(), 'name' ); + } + + /** + * Get store tax classes as slugs. + * + * @since 3.0.0 + * @return array Array of class slugs ("reduced-rate", "zero-rate", etc). + */ + public static function get_tax_class_slugs() { + return wp_list_pluck( self::get_tax_rate_classes(), 'slug' ); + } + + /** + * Create a new tax class. + * + * @since 3.7.0 + * @param string $name Name of the tax class to add. + * @param string $slug (optional) Slug of the tax class to add. Defaults to sanitized name. + * @return WP_Error|array Returns name and slug (array) if the tax class is created, or WP_Error if something went wrong. + */ + public static function create_tax_class( $name, $slug = '' ) { + global $wpdb; + + if ( empty( $name ) ) { + return new WP_Error( 'tax_class_invalid_name', __( 'Tax class requires a valid name', 'woocommerce' ) ); + } + + $existing = self::get_tax_classes(); + $existing_slugs = self::get_tax_class_slugs(); + + if ( in_array( $name, $existing, true ) ) { + return new WP_Error( 'tax_class_exists', __( 'Tax class already exists', 'woocommerce' ) ); + } + + if ( ! $slug ) { + $slug = sanitize_title( $name ); + } + + if ( in_array( $slug, $existing_slugs, true ) ) { + return new WP_Error( 'tax_class_slug_exists', __( 'Tax class slug already exists', 'woocommerce' ) ); + } + + $insert = $wpdb->insert( + $wpdb->wc_tax_rate_classes, + array( + 'name' => $name, + 'slug' => $slug, + ) + ); + + if ( is_wp_error( $insert ) ) { + return new WP_Error( 'tax_class_insert_error', $insert->get_error_message() ); + } + + wp_cache_delete( 'tax-rate-classes', 'taxes' ); + + return array( + 'name' => $name, + 'slug' => $slug, + ); + } + + /** + * Get an existing tax class. + * + * @since 3.7.0 + * @param string $field Field to get by. Valid values are id, name, or slug. + * @param string|int $item Item to get. + * @return array|bool Returns the tax class as an array. False if not found. + */ + public static function get_tax_class_by( $field, $item ) { + if ( ! in_array( $field, array( 'id', 'name', 'slug' ), true ) ) { + return new WP_Error( 'invalid_field', __( 'Invalid field', 'woocommerce' ) ); + } + + if ( 'id' === $field ) { + $field = 'tax_rate_class_id'; + } + + $matches = wp_list_filter( + self::get_tax_rate_classes(), + array( + $field => $item, + ) + ); + + if ( ! $matches ) { + return false; + } + + $tax_class = current( $matches ); + + return array( + 'name' => $tax_class->name, + 'slug' => $tax_class->slug, + ); + } + + /** + * Delete an existing tax class. + * + * @since 3.7.0 + * @param string $field Field to delete by. Valid values are id, name, or slug. + * @param string|int $item Item to delete. + * @return WP_Error|bool Returns true if deleted successfully, false if nothing was deleted, or WP_Error if there is an invalid request. + */ + public static function delete_tax_class_by( $field, $item ) { + global $wpdb; + + if ( ! in_array( $field, array( 'id', 'name', 'slug' ), true ) ) { + return new WP_Error( 'invalid_field', __( 'Invalid field', 'woocommerce' ) ); + } + + $tax_class = self::get_tax_class_by( $field, $item ); + + if ( ! $tax_class ) { + return new WP_Error( 'invalid_tax_class', __( 'Invalid tax class', 'woocommerce' ) ); + } + + if ( 'id' === $field ) { + $field = 'tax_rate_class_id'; + } + + $delete = $wpdb->delete( + $wpdb->wc_tax_rate_classes, + array( + $field => $item, + ) + ); + + if ( $delete ) { + // Delete associated tax rates. + $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_class = %s;", $tax_class['slug'] ) ); + $wpdb->query( "DELETE locations FROM {$wpdb->prefix}woocommerce_tax_rate_locations locations LEFT JOIN {$wpdb->prefix}woocommerce_tax_rates rates ON rates.tax_rate_id = locations.tax_rate_id WHERE rates.tax_rate_id IS NULL;" ); + } + + wp_cache_delete( 'tax-rate-classes', 'taxes' ); + WC_Cache_Helper::invalidate_cache_group( 'taxes' ); + + return (bool) $delete; + } + + /** + * Format the city. + * + * @param string $city Value to format. + * @return string + */ + private static function format_tax_rate_city( $city ) { + return strtoupper( trim( $city ) ); + } + + /** + * Format the state. + * + * @param string $state Value to format. + * @return string + */ + private static function format_tax_rate_state( $state ) { + $state = strtoupper( $state ); + return ( '*' === $state ) ? '' : $state; + } + + /** + * Format the country. + * + * @param string $country Value to format. + * @return string + */ + private static function format_tax_rate_country( $country ) { + $country = strtoupper( $country ); + return ( '*' === $country ) ? '' : $country; + } + + /** + * Format the tax rate name. + * + * @param string $name Value to format. + * @return string + */ + private static function format_tax_rate_name( $name ) { + return $name ? $name : __( 'Tax', 'woocommerce' ); + } + + /** + * Format the rate. + * + * @param float $rate Value to format. + * @return string + */ + private static function format_tax_rate( $rate ) { + return number_format( (float) $rate, 4, '.', '' ); + } + + /** + * Format the priority. + * + * @param string $priority Value to format. + * @return int + */ + private static function format_tax_rate_priority( $priority ) { + return absint( $priority ); + } + + /** + * Format the class. + * + * @param string $class Value to format. + * @return string + */ + public static function format_tax_rate_class( $class ) { + $class = sanitize_title( $class ); + $classes = self::get_tax_class_slugs(); + if ( ! in_array( $class, $classes, true ) ) { + $class = ''; + } + return ( 'standard' === $class ) ? '' : $class; + } + + /** + * Prepare and format tax rate for DB insertion. + * + * @param array $tax_rate Tax rate to format. + * @return array + */ + private static function prepare_tax_rate( $tax_rate ) { + foreach ( $tax_rate as $key => $value ) { + if ( method_exists( __CLASS__, 'format_' . $key ) ) { + if ( 'tax_rate_state' === $key ) { + $tax_rate[ $key ] = call_user_func( array( __CLASS__, 'format_' . $key ), sanitize_key( $value ) ); + } else { + $tax_rate[ $key ] = call_user_func( array( __CLASS__, 'format_' . $key ), $value ); + } + } + } + return $tax_rate; + } + + /** + * Insert a new tax rate. + * + * Internal use only. + * + * @since 2.3.0 + * + * @param array $tax_rate Tax rate to insert. + * @return int tax rate id + */ + public static function _insert_tax_rate( $tax_rate ) { + global $wpdb; + + $wpdb->insert( $wpdb->prefix . 'woocommerce_tax_rates', self::prepare_tax_rate( $tax_rate ) ); + + $tax_rate_id = $wpdb->insert_id; + + WC_Cache_Helper::invalidate_cache_group( 'taxes' ); + + do_action( 'woocommerce_tax_rate_added', $tax_rate_id, $tax_rate ); + + return $tax_rate_id; + } + + /** + * Get tax rate. + * + * Internal use only. + * + * @since 2.5.0 + * + * @param int $tax_rate_id Tax rate ID. + * @param string $output_type Type of output. + * @return array|object + */ + public static function _get_tax_rate( $tax_rate_id, $output_type = ARRAY_A ) { + global $wpdb; + + return $wpdb->get_row( + $wpdb->prepare( + " + SELECT * + FROM {$wpdb->prefix}woocommerce_tax_rates + WHERE tax_rate_id = %d + ", + $tax_rate_id + ), + $output_type + ); + } + + /** + * Update a tax rate. + * + * Internal use only. + * + * @since 2.3.0 + * + * @param int $tax_rate_id Tax rate to update. + * @param array $tax_rate Tax rate values. + */ + public static function _update_tax_rate( $tax_rate_id, $tax_rate ) { + global $wpdb; + + $tax_rate_id = absint( $tax_rate_id ); + + $wpdb->update( + $wpdb->prefix . 'woocommerce_tax_rates', + self::prepare_tax_rate( $tax_rate ), + array( + 'tax_rate_id' => $tax_rate_id, + ) + ); + + WC_Cache_Helper::invalidate_cache_group( 'taxes' ); + + do_action( 'woocommerce_tax_rate_updated', $tax_rate_id, $tax_rate ); + } + + /** + * Delete a tax rate from the database. + * + * Internal use only. + * + * @since 2.3.0 + * @param int $tax_rate_id Tax rate to delete. + */ + public static function _delete_tax_rate( $tax_rate_id ) { + global $wpdb; + + $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_tax_rate_locations WHERE tax_rate_id = %d;", $tax_rate_id ) ); + $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %d;", $tax_rate_id ) ); + + WC_Cache_Helper::invalidate_cache_group( 'taxes' ); + + do_action( 'woocommerce_tax_rate_deleted', $tax_rate_id ); + } + + /** + * Update postcodes for a tax rate in the DB. + * + * Internal use only. + * + * @since 2.3.0 + * + * @param int $tax_rate_id Tax rate to update. + * @param string $postcodes String of postcodes separated by ; characters. + */ + public static function _update_tax_rate_postcodes( $tax_rate_id, $postcodes ) { + if ( ! is_array( $postcodes ) ) { + $postcodes = explode( ';', $postcodes ); + } + // No normalization - postcodes are matched against both normal and formatted versions to support wildcards. + foreach ( $postcodes as $key => $postcode ) { + $postcodes[ $key ] = strtoupper( trim( str_replace( chr( 226 ) . chr( 128 ) . chr( 166 ), '...', $postcode ) ) ); + } + self::update_tax_rate_locations( $tax_rate_id, array_diff( array_filter( $postcodes ), array( '*' ) ), 'postcode' ); + } + + /** + * Update cities for a tax rate in the DB. + * + * Internal use only. + * + * @since 2.3.0 + * + * @param int $tax_rate_id Tax rate to update. + * @param string $cities Cities to set. + */ + public static function _update_tax_rate_cities( $tax_rate_id, $cities ) { + if ( ! is_array( $cities ) ) { + $cities = explode( ';', $cities ); + } + $cities = array_filter( array_diff( array_map( array( __CLASS__, 'format_tax_rate_city' ), $cities ), array( '*' ) ) ); + + self::update_tax_rate_locations( $tax_rate_id, $cities, 'city' ); + } + + /** + * Updates locations (postcode and city). + * + * Internal use only. + * + * @since 2.3.0 + * + * @param int $tax_rate_id Tax rate ID to update. + * @param array $values Values to set. + * @param string $type Location type. + */ + private static function update_tax_rate_locations( $tax_rate_id, $values, $type ) { + global $wpdb; + + $tax_rate_id = absint( $tax_rate_id ); + + $wpdb->query( + $wpdb->prepare( + "DELETE FROM {$wpdb->prefix}woocommerce_tax_rate_locations WHERE tax_rate_id = %d AND location_type = %s;", + $tax_rate_id, + $type + ) + ); + + if ( count( $values ) > 0 ) { + $sql = "( '" . implode( "', $tax_rate_id, '" . esc_sql( $type ) . "' ),( '", array_map( 'esc_sql', $values ) ) . "', $tax_rate_id, '" . esc_sql( $type ) . "' )"; + + $wpdb->query( "INSERT INTO {$wpdb->prefix}woocommerce_tax_rate_locations ( location_code, tax_rate_id, location_type ) VALUES $sql;" ); // @codingStandardsIgnoreLine. + } + + WC_Cache_Helper::invalidate_cache_group( 'taxes' ); + } + + /** + * Used by admin settings page. + * + * @param string $tax_class Tax class slug. + * + * @return array|null|object + */ + public static function get_rates_for_tax_class( $tax_class ) { + global $wpdb; + + // Get all the rates and locations. Snagging all at once should significantly cut down on the number of queries. + $rates = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM `{$wpdb->prefix}woocommerce_tax_rates` WHERE `tax_rate_class` = %s;", sanitize_title( $tax_class ) ) ); + $locations = $wpdb->get_results( "SELECT * FROM `{$wpdb->prefix}woocommerce_tax_rate_locations`" ); + + if ( ! empty( $rates ) ) { + // Set the rates keys equal to their ids. + $rates = array_combine( wp_list_pluck( $rates, 'tax_rate_id' ), $rates ); + } + + // Drop the locations into the rates array. + foreach ( $locations as $location ) { + // Don't set them for unexistent rates. + if ( ! isset( $rates[ $location->tax_rate_id ] ) ) { + continue; + } + // If the rate exists, initialize the array before appending to it. + if ( ! isset( $rates[ $location->tax_rate_id ]->{$location->location_type} ) ) { + $rates[ $location->tax_rate_id ]->{$location->location_type} = array(); + } + $rates[ $location->tax_rate_id ]->{$location->location_type}[] = $location->location_code; + } + + foreach ( $rates as $rate_id => $rate ) { + $rates[ $rate_id ]->postcode_count = isset( $rates[ $rate_id ]->postcode ) ? count( $rates[ $rate_id ]->postcode ) : 0; + $rates[ $rate_id ]->city_count = isset( $rates[ $rate_id ]->city ) ? count( $rates[ $rate_id ]->city ) : 0; + } + + $rates = self::sort_rates( $rates ); + + return $rates; + } +} +WC_Tax::init(); diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-template-loader.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-template-loader.php new file mode 100644 index 0000000..5a32337 --- /dev/null +++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-template-loader.php @@ -0,0 +1,586 @@ +plugin_path() . '/templates/' . $cs_template; + } else { + $template = WC()->plugin_path() . '/templates/' . $default_file; + } + } + } + + return $template; + } + + /** + * Get the default filename for a template. + * + * @since 3.0.0 + * @return string + */ + private static function get_template_loader_default_file() { + if ( is_singular( 'product' ) ) { + $default_file = 'single-product.php'; + } elseif ( is_product_taxonomy() ) { + $object = get_queried_object(); + + if ( is_tax( 'product_cat' ) || is_tax( 'product_tag' ) ) { + $default_file = 'taxonomy-' . $object->taxonomy . '.php'; + } else { + $default_file = 'archive-product.php'; + } + } elseif ( is_post_type_archive( 'product' ) || is_page( wc_get_page_id( 'shop' ) ) ) { + $default_file = self::$theme_support ? 'archive-product.php' : ''; + } else { + $default_file = ''; + } + return $default_file; + } + + /** + * Get an array of filenames to search for a given template. + * + * @since 3.0.0 + * @param string $default_file The default file name. + * @return string[] + */ + private static function get_template_loader_files( $default_file ) { + $templates = apply_filters( 'woocommerce_template_loader_files', array(), $default_file ); + $templates[] = 'woocommerce.php'; + + if ( is_page_template() ) { + $page_template = get_page_template_slug(); + + if ( $page_template ) { + $validated_file = validate_file( $page_template ); + if ( 0 === $validated_file ) { + $templates[] = $page_template; + } else { + error_log( "WooCommerce: Unable to validate template path: \"$page_template\". Error Code: $validated_file." ); + } + } + } + + if ( is_singular( 'product' ) ) { + $object = get_queried_object(); + $name_decoded = urldecode( $object->post_name ); + if ( $name_decoded !== $object->post_name ) { + $templates[] = "single-product-{$name_decoded}.php"; + } + $templates[] = "single-product-{$object->post_name}.php"; + } + + if ( is_product_taxonomy() ) { + $object = get_queried_object(); + + $templates[] = 'taxonomy-' . $object->taxonomy . '-' . $object->slug . '.php'; + $templates[] = WC()->template_path() . 'taxonomy-' . $object->taxonomy . '-' . $object->slug . '.php'; + $templates[] = 'taxonomy-' . $object->taxonomy . '.php'; + $templates[] = WC()->template_path() . 'taxonomy-' . $object->taxonomy . '.php'; + + if ( is_tax( 'product_cat' ) || is_tax( 'product_tag' ) ) { + $cs_taxonomy = str_replace( '_', '-', $object->taxonomy ); + $cs_default = str_replace( '_', '-', $default_file ); + $templates[] = 'taxonomy-' . $object->taxonomy . '-' . $object->slug . '.php'; + $templates[] = WC()->template_path() . 'taxonomy-' . $cs_taxonomy . '-' . $object->slug . '.php'; + $templates[] = 'taxonomy-' . $object->taxonomy . '.php'; + $templates[] = WC()->template_path() . 'taxonomy-' . $cs_taxonomy . '.php'; + $templates[] = $cs_default; + } + } + + $templates[] = $default_file; + if ( isset( $cs_default ) ) { + $templates[] = WC()->template_path() . $cs_default; + } + $templates[] = WC()->template_path() . $default_file; + + return array_unique( $templates ); + } + + /** + * Load comments template. + * + * @param string $template template to load. + * @return string + */ + public static function comments_template_loader( $template ) { + if ( get_post_type() !== 'product' ) { + return $template; + } + + $check_dirs = array( + trailingslashit( get_stylesheet_directory() ) . WC()->template_path(), + trailingslashit( get_template_directory() ) . WC()->template_path(), + trailingslashit( get_stylesheet_directory() ), + trailingslashit( get_template_directory() ), + trailingslashit( WC()->plugin_path() ) . 'templates/', + ); + + if ( WC_TEMPLATE_DEBUG_MODE ) { + $check_dirs = array( array_pop( $check_dirs ) ); + } + + foreach ( $check_dirs as $dir ) { + if ( file_exists( trailingslashit( $dir ) . 'single-product-reviews.php' ) ) { + return trailingslashit( $dir ) . 'single-product-reviews.php'; + } + } + } + + /** + * Unsupported theme compatibility methods. + */ + + /** + * Hook in methods to enhance the unsupported theme experience on pages. + * + * @since 3.3.0 + */ + public static function unsupported_theme_init() { + if ( 0 < self::$shop_page_id ) { + if ( is_product_taxonomy() ) { + self::unsupported_theme_tax_archive_init(); + } elseif ( is_product() ) { + self::unsupported_theme_product_page_init(); + } else { + self::unsupported_theme_shop_page_init(); + } + } + } + + /** + * Hook in methods to enhance the unsupported theme experience on the Shop page. + * + * @since 3.3.0 + */ + private static function unsupported_theme_shop_page_init() { + add_filter( 'the_content', array( __CLASS__, 'unsupported_theme_shop_content_filter' ), 10 ); + add_filter( 'the_title', array( __CLASS__, 'unsupported_theme_title_filter' ), 10, 2 ); + add_filter( 'comments_number', array( __CLASS__, 'unsupported_theme_comments_number_filter' ) ); + } + + /** + * Hook in methods to enhance the unsupported theme experience on Product pages. + * + * @since 3.3.0 + */ + private static function unsupported_theme_product_page_init() { + add_filter( 'the_content', array( __CLASS__, 'unsupported_theme_product_content_filter' ), 10 ); + add_filter( 'post_thumbnail_html', array( __CLASS__, 'unsupported_theme_single_featured_image_filter' ) ); + add_filter( 'woocommerce_product_tabs', array( __CLASS__, 'unsupported_theme_remove_review_tab' ) ); + remove_action( 'woocommerce_before_main_content', 'woocommerce_output_content_wrapper', 10 ); + remove_action( 'woocommerce_after_main_content', 'woocommerce_output_content_wrapper_end', 10 ); + add_theme_support( 'wc-product-gallery-zoom' ); + add_theme_support( 'wc-product-gallery-lightbox' ); + add_theme_support( 'wc-product-gallery-slider' ); + } + + /** + * Enhance the unsupported theme experience on Product Category and Attribute pages by rendering + * those pages using the single template and shortcode-based content. To do this we make a dummy + * post and set a shortcode as the post content. This approach is adapted from bbPress. + * + * @since 3.3.0 + */ + private static function unsupported_theme_tax_archive_init() { + global $wp_query, $post; + + $queried_object = get_queried_object(); + $args = self::get_current_shop_view_args(); + $shortcode_args = array( + 'page' => $args->page, + 'columns' => $args->columns, + 'rows' => $args->rows, + 'orderby' => '', + 'order' => '', + 'paginate' => true, + 'cache' => false, + ); + + if ( is_product_category() ) { + $shortcode_args['category'] = sanitize_title( $queried_object->slug ); + } elseif ( taxonomy_is_product_attribute( $queried_object->taxonomy ) ) { + $shortcode_args['attribute'] = sanitize_title( $queried_object->taxonomy ); + $shortcode_args['terms'] = sanitize_title( $queried_object->slug ); + } elseif ( is_product_tag() ) { + $shortcode_args['tag'] = sanitize_title( $queried_object->slug ); + } else { + // Default theme archive for all other taxonomies. + return; + } + + // Description handling. + if ( ! empty( $queried_object->description ) && ( empty( $_GET['product-page'] ) || 1 === absint( $_GET['product-page'] ) ) ) { // WPCS: input var ok, CSRF ok. + $prefix = '
'; // WPCS: XSS ok.
+ } else {
+ $prefix = '';
+ }
+
+ add_filter( 'woocommerce_shortcode_products_query', array( __CLASS__, 'unsupported_archive_layered_nav_compatibility' ) );
+ $shortcode = new WC_Shortcode_Products( $shortcode_args );
+ remove_filter( 'woocommerce_shortcode_products_query', array( __CLASS__, 'unsupported_archive_layered_nav_compatibility' ) );
+ $shop_page = get_post( self::$shop_page_id );
+
+ $dummy_post_properties = array(
+ 'ID' => 0,
+ 'post_status' => 'publish',
+ 'post_author' => $shop_page->post_author,
+ 'post_parent' => 0,
+ 'post_type' => 'page',
+ 'post_date' => $shop_page->post_date,
+ 'post_date_gmt' => $shop_page->post_date_gmt,
+ 'post_modified' => $shop_page->post_modified,
+ 'post_modified_gmt' => $shop_page->post_modified_gmt,
+ 'post_content' => $prefix . $shortcode->get_content(),
+ 'post_title' => wc_clean( $queried_object->name ),
+ 'post_excerpt' => '',
+ 'post_content_filtered' => '',
+ 'post_mime_type' => '',
+ 'post_password' => '',
+ 'post_name' => $queried_object->slug,
+ 'guid' => '',
+ 'menu_order' => 0,
+ 'pinged' => '',
+ 'to_ping' => '',
+ 'ping_status' => '',
+ 'comment_status' => 'closed',
+ 'comment_count' => 0,
+ 'filter' => 'raw',
+ );
+
+ // Set the $post global.
+ $post = new WP_Post( (object) $dummy_post_properties ); // @codingStandardsIgnoreLine.
+
+ // Copy the new post global into the main $wp_query.
+ $wp_query->post = $post;
+ $wp_query->posts = array( $post );
+
+ // Prevent comments form from appearing.
+ $wp_query->post_count = 1;
+ $wp_query->is_404 = false;
+ $wp_query->is_page = true;
+ $wp_query->is_single = true;
+ $wp_query->is_archive = false;
+ $wp_query->is_tax = true;
+ $wp_query->max_num_pages = 0;
+
+ // Prepare everything for rendering.
+ setup_postdata( $post );
+ remove_all_filters( 'the_content' );
+ remove_all_filters( 'the_excerpt' );
+ add_filter( 'template_include', array( __CLASS__, 'force_single_template_filter' ) );
+ }
+
+ /**
+ * Add layered nav args to WP_Query args generated by the 'products' shortcode.
+ *
+ * @since 3.3.4
+ * @param array $query WP_Query args.
+ * @return array
+ */
+ public static function unsupported_archive_layered_nav_compatibility( $query ) {
+ foreach ( WC()->query->get_layered_nav_chosen_attributes() as $taxonomy => $data ) {
+ $query['tax_query'][] = array(
+ 'taxonomy' => $taxonomy,
+ 'field' => 'slug',
+ 'terms' => $data['terms'],
+ 'operator' => 'and' === $data['query_type'] ? 'AND' : 'IN',
+ 'include_children' => false,
+ );
+ }
+ return $query;
+ }
+
+ /**
+ * Force the loading of one of the single templates instead of whatever template was about to be loaded.
+ *
+ * @since 3.3.0
+ * @param string $template Path to template.
+ * @return string
+ */
+ public static function force_single_template_filter( $template ) {
+ $possible_templates = array(
+ 'page',
+ 'single',
+ 'singular',
+ 'index',
+ );
+
+ foreach ( $possible_templates as $possible_template ) {
+ $path = get_query_template( $possible_template );
+ if ( $path ) {
+ return $path;
+ }
+ }
+
+ return $template;
+ }
+
+ /**
+ * Get information about the current shop page view.
+ *
+ * @since 3.3.0
+ * @return array
+ */
+ private static function get_current_shop_view_args() {
+ return (object) array(
+ 'page' => absint( max( 1, absint( get_query_var( 'paged' ) ) ) ),
+ 'columns' => wc_get_default_products_per_row(),
+ 'rows' => wc_get_default_product_rows_per_page(),
+ );
+ }
+
+ /**
+ * Filter the title and insert WooCommerce content on the shop page.
+ *
+ * For non-WC themes, this will setup the main shop page to be shortcode based to improve default appearance.
+ *
+ * @since 3.3.0
+ * @param string $title Existing title.
+ * @param int $id ID of the post being filtered.
+ * @return string
+ */
+ public static function unsupported_theme_title_filter( $title, $id ) {
+ if ( self::$theme_support || ! $id !== self::$shop_page_id ) {
+ return $title;
+ }
+
+ if ( is_page( self::$shop_page_id ) || ( is_home() && 'page' === get_option( 'show_on_front' ) && absint( get_option( 'page_on_front' ) ) === self::$shop_page_id ) ) {
+ $args = self::get_current_shop_view_args();
+ $title_suffix = array();
+
+ if ( $args->page > 1 ) {
+ /* translators: %d: Page number. */
+ $title_suffix[] = sprintf( esc_html__( 'Page %d', 'woocommerce' ), $args->page );
+ }
+
+ if ( $title_suffix ) {
+ $title = $title . ' – ' . implode( ', ', $title_suffix );
+ }
+ }
+ return $title;
+ }
+
+ /**
+ * Filter the content and insert WooCommerce content on the shop page.
+ *
+ * For non-WC themes, this will setup the main shop page to be shortcode based to improve default appearance.
+ *
+ * @since 3.3.0
+ * @param string $content Existing post content.
+ * @return string
+ */
+ public static function unsupported_theme_shop_content_filter( $content ) {
+ global $wp_query;
+
+ if ( self::$theme_support || ! is_main_query() || ! in_the_loop() ) {
+ return $content;
+ }
+
+ self::$in_content_filter = true;
+
+ // Remove the filter we're in to avoid nested calls.
+ remove_filter( 'the_content', array( __CLASS__, 'unsupported_theme_shop_content_filter' ) );
+
+ // Unsupported theme shop page.
+ if ( is_page( self::$shop_page_id ) ) {
+ $args = self::get_current_shop_view_args();
+ $shortcode = new WC_Shortcode_Products(
+ array_merge(
+ WC()->query->get_catalog_ordering_args(),
+ array(
+ 'page' => $args->page,
+ 'columns' => $args->columns,
+ 'rows' => $args->rows,
+ 'orderby' => '',
+ 'order' => '',
+ 'paginate' => true,
+ 'cache' => false,
+ )
+ ),
+ 'products'
+ );
+
+ // Allow queries to run e.g. layered nav.
+ add_action( 'pre_get_posts', array( WC()->query, 'product_query' ) );
+
+ $content = $content . $shortcode->get_content();
+
+ // Remove actions and self to avoid nested calls.
+ remove_action( 'pre_get_posts', array( WC()->query, 'product_query' ) );
+ WC()->query->remove_ordering_args();
+ }
+
+ self::$in_content_filter = false;
+
+ return $content;
+ }
+
+ /**
+ * Filter the content and insert WooCommerce content on the shop page.
+ *
+ * For non-WC themes, this will setup the main shop page to be shortcode based to improve default appearance.
+ *
+ * @since 3.3.0
+ * @param string $content Existing post content.
+ * @return string
+ */
+ public static function unsupported_theme_product_content_filter( $content ) {
+ global $wp_query;
+
+ if ( self::$theme_support || ! is_main_query() || ! in_the_loop() ) {
+ return $content;
+ }
+
+ self::$in_content_filter = true;
+
+ // Remove the filter we're in to avoid nested calls.
+ remove_filter( 'the_content', array( __CLASS__, 'unsupported_theme_product_content_filter' ) );
+
+ if ( is_product() ) {
+ $content = do_shortcode( '[product_page id="' . get_the_ID() . '" show_title=0 status="any"]' );
+ }
+
+ self::$in_content_filter = false;
+
+ return $content;
+ }
+
+ /**
+ * Suppress the comments number on the Shop page for unsupported themes since there is no commenting on the Shop page.
+ *
+ * @since 3.4.5
+ * @param string $comments_number The comments number text.
+ * @return string
+ */
+ public static function unsupported_theme_comments_number_filter( $comments_number ) {
+ if ( is_page( self::$shop_page_id ) ) {
+ return '';
+ }
+
+ return $comments_number;
+ }
+
+ /**
+ * Are we filtering content for unsupported themes?
+ *
+ * @since 3.3.2
+ * @return bool
+ */
+ public static function in_content_filter() {
+ return (bool) self::$in_content_filter;
+ }
+
+ /**
+ * Prevent the main featured image on product pages because there will be another featured image
+ * in the gallery.
+ *
+ * @since 3.3.0
+ * @param string $html Img element HTML.
+ * @return string
+ */
+ public static function unsupported_theme_single_featured_image_filter( $html ) {
+ if ( self::in_content_filter() || ! is_product() || ! is_main_query() ) {
+ return $html;
+ }
+
+ return '';
+ }
+
+ /**
+ * Remove the Review tab and just use the regular comment form.
+ *
+ * @param array $tabs Tab info.
+ * @return array
+ */
+ public static function unsupported_theme_remove_review_tab( $tabs ) {
+ unset( $tabs['reviews'] );
+ return $tabs;
+ }
+}
+
+add_action( 'init', array( 'WC_Template_Loader', 'init' ) );
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-tracker.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-tracker.php
new file mode 100644
index 0000000..27a3696
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-tracker.php
@@ -0,0 +1,763 @@
+ apply_filters( 'woocommerce_tracker_last_send_interval', strtotime( '-1 week' ) ) ) {
+ return;
+ }
+ } else {
+ // Make sure there is at least a 1 hour delay between override sends, we don't want duplicate calls due to double clicking links.
+ $last_send = self::get_last_send_time();
+ if ( $last_send && $last_send > strtotime( '-1 hours' ) ) {
+ return;
+ }
+ }
+
+ // Update time first before sending to ensure it is set.
+ update_option( 'woocommerce_tracker_last_send', time() );
+
+ $params = self::get_tracking_data();
+ wp_safe_remote_post(
+ self::$api_url,
+ array(
+ 'method' => 'POST',
+ 'timeout' => 45,
+ 'redirection' => 5,
+ 'httpversion' => '1.0',
+ 'blocking' => false,
+ 'headers' => array( 'user-agent' => 'WooCommerceTracker/' . md5( esc_url_raw( home_url( '/' ) ) ) . ';' ),
+ 'body' => wp_json_encode( $params ),
+ 'cookies' => array(),
+ )
+ );
+ }
+
+ /**
+ * Get the last time tracking data was sent.
+ *
+ * @return int|bool
+ */
+ private static function get_last_send_time() {
+ return apply_filters( 'woocommerce_tracker_last_send_time', get_option( 'woocommerce_tracker_last_send', false ) );
+ }
+
+ /**
+ * Test whether this site is a staging site according to the Jetpack criteria.
+ *
+ * With Jetpack 8.1+, Jetpack::is_staging_site has been deprecated.
+ * \Automattic\Jetpack\Status::is_staging_site is the replacement.
+ * However, there are version of JP where \Automattic\Jetpack\Status exists, but does *not* contain is_staging_site method,
+ * so with those, code still needs to use the previous check as a fallback.
+ *
+ * @return bool
+ */
+ private static function is_jetpack_staging_site() {
+ if ( class_exists( '\Automattic\Jetpack\Status' ) ) {
+ // Preferred way of checking with Jetpack 8.1+.
+ $jp_status = new \Automattic\Jetpack\Status();
+ if ( is_callable( array( $jp_status, 'is_staging_site' ) ) ) {
+ return $jp_status->is_staging_site();
+ }
+ }
+
+ return ( class_exists( 'Jetpack' ) && is_callable( 'Jetpack::is_staging_site' ) && Jetpack::is_staging_site() );
+ }
+
+ /**
+ * Get all the tracking data.
+ *
+ * @return array
+ */
+ private static function get_tracking_data() {
+ $data = array();
+
+ // General site info.
+ $data['url'] = home_url();
+ $data['email'] = apply_filters( 'woocommerce_tracker_admin_email', get_option( 'admin_email' ) );
+ $data['theme'] = self::get_theme_info();
+
+ // WordPress Info.
+ $data['wp'] = self::get_wordpress_info();
+
+ // Server Info.
+ $data['server'] = self::get_server_info();
+
+ // Plugin info.
+ $all_plugins = self::get_all_plugins();
+ $data['active_plugins'] = $all_plugins['active_plugins'];
+ $data['inactive_plugins'] = $all_plugins['inactive_plugins'];
+
+ // Jetpack & WooCommerce Connect.
+
+ $data['jetpack_version'] = Constants::is_defined( 'JETPACK__VERSION' ) ? Constants::get_constant( 'JETPACK__VERSION' ) : 'none';
+ $data['jetpack_connected'] = ( class_exists( 'Jetpack' ) && is_callable( 'Jetpack::is_active' ) && Jetpack::is_active() ) ? 'yes' : 'no';
+ $data['jetpack_is_staging'] = self::is_jetpack_staging_site() ? 'yes' : 'no';
+ $data['connect_installed'] = class_exists( 'WC_Connect_Loader' ) ? 'yes' : 'no';
+ $data['connect_active'] = ( class_exists( 'WC_Connect_Loader' ) && wp_next_scheduled( 'wc_connect_fetch_service_schemas' ) ) ? 'yes' : 'no';
+ $data['helper_connected'] = self::get_helper_connected();
+
+ // Store count info.
+ $data['users'] = self::get_user_counts();
+ $data['products'] = self::get_product_counts();
+ $data['orders'] = self::get_orders();
+ $data['reviews'] = self::get_review_counts();
+ $data['categories'] = self::get_category_counts();
+
+ // Payment gateway info.
+ $data['gateways'] = self::get_active_payment_gateways();
+
+ // Shipping method info.
+ $data['shipping_methods'] = self::get_active_shipping_methods();
+
+ // Get all WooCommerce options info.
+ $data['settings'] = self::get_all_woocommerce_options_values();
+
+ // Template overrides.
+ $data['template_overrides'] = self::get_all_template_overrides();
+
+ // Template overrides.
+ $data['admin_user_agents'] = self::get_admin_user_agents();
+
+ // Cart & checkout tech (blocks or shortcodes).
+ $data['cart_checkout'] = self::get_cart_checkout_info();
+
+ return apply_filters( 'woocommerce_tracker_data', $data );
+ }
+
+ /**
+ * Get the current theme info, theme name and version.
+ *
+ * @return array
+ */
+ public static function get_theme_info() {
+ $theme_data = wp_get_theme();
+ $theme_child_theme = wc_bool_to_string( is_child_theme() );
+ $theme_wc_support = wc_bool_to_string( current_theme_supports( 'woocommerce' ) );
+
+ return array(
+ 'name' => $theme_data->Name, // @phpcs:ignore
+ 'version' => $theme_data->Version, // @phpcs:ignore
+ 'child_theme' => $theme_child_theme,
+ 'wc_support' => $theme_wc_support,
+ );
+ }
+
+ /**
+ * Get WordPress related data.
+ *
+ * @return array
+ */
+ private static function get_wordpress_info() {
+ $wp_data = array();
+
+ $memory = wc_let_to_num( WP_MEMORY_LIMIT );
+
+ if ( function_exists( 'memory_get_usage' ) ) {
+ $system_memory = wc_let_to_num( @ini_get( 'memory_limit' ) );
+ $memory = max( $memory, $system_memory );
+ }
+
+ // WordPress 5.5+ environment type specification.
+ // 'production' is the default in WP, thus using it as a default here, too.
+ $environment_type = 'production';
+ if ( function_exists( 'wp_get_environment_type' ) ) {
+ $environment_type = wp_get_environment_type();
+ }
+
+ $wp_data['memory_limit'] = size_format( $memory );
+ $wp_data['debug_mode'] = ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ? 'Yes' : 'No';
+ $wp_data['locale'] = get_locale();
+ $wp_data['version'] = get_bloginfo( 'version' );
+ $wp_data['multisite'] = is_multisite() ? 'Yes' : 'No';
+ $wp_data['env_type'] = $environment_type;
+
+ return $wp_data;
+ }
+
+ /**
+ * Get server related info.
+ *
+ * @return array
+ */
+ private static function get_server_info() {
+ $server_data = array();
+
+ if ( ! empty( $_SERVER['SERVER_SOFTWARE'] ) ) {
+ $server_data['software'] = $_SERVER['SERVER_SOFTWARE']; // @phpcs:ignore
+ }
+
+ if ( function_exists( 'phpversion' ) ) {
+ $server_data['php_version'] = phpversion();
+ }
+
+ if ( function_exists( 'ini_get' ) ) {
+ $server_data['php_post_max_size'] = size_format( wc_let_to_num( ini_get( 'post_max_size' ) ) );
+ $server_data['php_time_limt'] = ini_get( 'max_execution_time' );
+ $server_data['php_max_input_vars'] = ini_get( 'max_input_vars' );
+ $server_data['php_suhosin'] = extension_loaded( 'suhosin' ) ? 'Yes' : 'No';
+ }
+
+ $database_version = wc_get_server_database_version();
+ $server_data['mysql_version'] = $database_version['number'];
+
+ $server_data['php_max_upload_size'] = size_format( wp_max_upload_size() );
+ $server_data['php_default_timezone'] = date_default_timezone_get();
+ $server_data['php_soap'] = class_exists( 'SoapClient' ) ? 'Yes' : 'No';
+ $server_data['php_fsockopen'] = function_exists( 'fsockopen' ) ? 'Yes' : 'No';
+ $server_data['php_curl'] = function_exists( 'curl_init' ) ? 'Yes' : 'No';
+
+ return $server_data;
+ }
+
+ /**
+ * Get all plugins grouped into activated or not.
+ *
+ * @return array
+ */
+ private static function get_all_plugins() {
+ // Ensure get_plugins function is loaded.
+ if ( ! function_exists( 'get_plugins' ) ) {
+ include ABSPATH . '/wp-admin/includes/plugin.php';
+ }
+
+ $plugins = get_plugins();
+ $active_plugins_keys = get_option( 'active_plugins', array() );
+ $active_plugins = array();
+
+ foreach ( $plugins as $k => $v ) {
+ // Take care of formatting the data how we want it.
+ $formatted = array();
+ $formatted['name'] = strip_tags( $v['Name'] );
+ if ( isset( $v['Version'] ) ) {
+ $formatted['version'] = strip_tags( $v['Version'] );
+ }
+ if ( isset( $v['Author'] ) ) {
+ $formatted['author'] = strip_tags( $v['Author'] );
+ }
+ if ( isset( $v['Network'] ) ) {
+ $formatted['network'] = strip_tags( $v['Network'] );
+ }
+ if ( isset( $v['PluginURI'] ) ) {
+ $formatted['plugin_uri'] = strip_tags( $v['PluginURI'] );
+ }
+ if ( in_array( $k, $active_plugins_keys ) ) {
+ // Remove active plugins from list so we can show active and inactive separately.
+ unset( $plugins[ $k ] );
+ $active_plugins[ $k ] = $formatted;
+ } else {
+ $plugins[ $k ] = $formatted;
+ }
+ }
+
+ return array(
+ 'active_plugins' => $active_plugins,
+ 'inactive_plugins' => $plugins,
+ );
+ }
+
+ /**
+ * Check to see if the helper is connected to woocommerce.com
+ *
+ * @return string
+ */
+ private static function get_helper_connected() {
+ if ( class_exists( 'WC_Helper_Options' ) && is_callable( 'WC_Helper_Options::get' ) ) {
+ $authenticated = WC_Helper_Options::get( 'auth' );
+ } else {
+ $authenticated = '';
+ }
+ return ( ! empty( $authenticated ) ) ? 'yes' : 'no';
+ }
+
+
+ /**
+ * Get user totals based on user role.
+ *
+ * @return array
+ */
+ private static function get_user_counts() {
+ $user_count = array();
+ $user_count_data = count_users();
+ $user_count['total'] = $user_count_data['total_users'];
+
+ // Get user count based on user role.
+ foreach ( $user_count_data['avail_roles'] as $role => $count ) {
+ $user_count[ $role ] = $count;
+ }
+
+ return $user_count;
+ }
+
+ /**
+ * Get product totals based on product type.
+ *
+ * @return array
+ */
+ public static function get_product_counts() {
+ $product_count = array();
+ $product_count_data = wp_count_posts( 'product' );
+ $product_count['total'] = $product_count_data->publish;
+
+ $product_statuses = get_terms( 'product_type', array( 'hide_empty' => 0 ) );
+ foreach ( $product_statuses as $product_status ) {
+ $product_count[ $product_status->name ] = $product_status->count;
+ }
+
+ return $product_count;
+ }
+
+ /**
+ * Get order counts
+ *
+ * @return array
+ */
+ private static function get_order_counts() {
+ $order_count = array();
+ $order_count_data = wp_count_posts( 'shop_order' );
+ foreach ( wc_get_order_statuses() as $status_slug => $status_name ) {
+ $order_count[ $status_slug ] = $order_count_data->{ $status_slug };
+ }
+ return $order_count;
+ }
+
+ /**
+ * Combine all order data.
+ *
+ * @return array
+ */
+ private static function get_orders() {
+ $order_dates = self::get_order_dates();
+ $order_counts = self::get_order_counts();
+ $order_totals = self::get_order_totals();
+
+ return array_merge( $order_dates, $order_counts, $order_totals );
+ }
+
+ /**
+ * Get review counts for different statuses.
+ *
+ * @return array
+ */
+ private static function get_review_counts() {
+ global $wpdb;
+ $review_count = array( 'total' => 0 );
+ $status_map = array(
+ '0' => 'pending',
+ '1' => 'approved',
+ 'trash' => 'trash',
+ 'spam' => 'spam',
+ );
+ $counts = $wpdb->get_results(
+ "
+ SELECT comment_approved, COUNT(*) AS num_reviews
+ FROM {$wpdb->comments}
+ WHERE comment_type = 'review'
+ GROUP BY comment_approved
+ ",
+ ARRAY_A
+ );
+
+ if ( ! $counts ) {
+ return $review_count;
+ }
+
+ foreach ( $counts as $count ) {
+ $status = $count['comment_approved'];
+ if ( array_key_exists( $status, $status_map ) ) {
+ $review_count[ $status_map[ $status ] ] = $count['num_reviews'];
+ }
+ $review_count['total'] += $count['num_reviews'];
+ }
+
+ return $review_count;
+ }
+
+ /**
+ * Get the number of product categories.
+ *
+ * @return int
+ */
+ private static function get_category_counts() {
+ return wp_count_terms( 'product_cat' );
+ }
+
+ /**
+ * Get a list of all active payment gateways.
+ *
+ * @return array
+ */
+ private static function get_active_payment_gateways() {
+ $active_gateways = array();
+ $gateways = WC()->payment_gateways->payment_gateways();
+ foreach ( $gateways as $id => $gateway ) {
+ if ( isset( $gateway->enabled ) && 'yes' === $gateway->enabled ) {
+ $active_gateways[ $id ] = array(
+ 'title' => $gateway->title,
+ 'supports' => $gateway->supports,
+ );
+ }
+ }
+
+ return $active_gateways;
+ }
+
+ /**
+ * Get a list of all active shipping methods.
+ *
+ * @return array
+ */
+ private static function get_active_shipping_methods() {
+ $active_methods = array();
+ $shipping_methods = WC()->shipping()->get_shipping_methods();
+ foreach ( $shipping_methods as $id => $shipping_method ) {
+ if ( isset( $shipping_method->enabled ) && 'yes' === $shipping_method->enabled ) {
+ $active_methods[ $id ] = array(
+ 'title' => $shipping_method->title,
+ 'tax_status' => $shipping_method->tax_status,
+ );
+ }
+ }
+
+ return $active_methods;
+ }
+
+ /**
+ * Get all options starting with woocommerce_ prefix.
+ *
+ * @return array
+ */
+ private static function get_all_woocommerce_options_values() {
+ return array(
+ 'version' => WC()->version,
+ 'currency' => get_woocommerce_currency(),
+ 'base_location' => WC()->countries->get_base_country(),
+ 'selling_locations' => WC()->countries->get_allowed_countries(),
+ 'api_enabled' => get_option( 'woocommerce_api_enabled' ),
+ 'weight_unit' => get_option( 'woocommerce_weight_unit' ),
+ 'dimension_unit' => get_option( 'woocommerce_dimension_unit' ),
+ 'download_method' => get_option( 'woocommerce_file_download_method' ),
+ 'download_require_login' => get_option( 'woocommerce_downloads_require_login' ),
+ 'calc_taxes' => get_option( 'woocommerce_calc_taxes' ),
+ 'coupons_enabled' => get_option( 'woocommerce_enable_coupons' ),
+ 'guest_checkout' => get_option( 'woocommerce_enable_guest_checkout' ),
+ 'secure_checkout' => get_option( 'woocommerce_force_ssl_checkout' ),
+ 'enable_signup_and_login_from_checkout' => get_option( 'woocommerce_enable_signup_and_login_from_checkout' ),
+ 'enable_myaccount_registration' => get_option( 'woocommerce_enable_myaccount_registration' ),
+ 'registration_generate_username' => get_option( 'woocommerce_registration_generate_username' ),
+ 'registration_generate_password' => get_option( 'woocommerce_registration_generate_password' ),
+ );
+ }
+
+ /**
+ * Look for any template override and return filenames.
+ *
+ * @return array
+ */
+ private static function get_all_template_overrides() {
+ $override_data = array();
+ $template_paths = apply_filters( 'woocommerce_template_overrides_scan_paths', array( 'WooCommerce' => WC()->plugin_path() . '/templates/' ) );
+ $scanned_files = array();
+
+ require_once WC()->plugin_path() . '/includes/admin/class-wc-admin-status.php';
+
+ foreach ( $template_paths as $plugin_name => $template_path ) {
+ $scanned_files[ $plugin_name ] = WC_Admin_Status::scan_template_files( $template_path );
+ }
+
+ foreach ( $scanned_files as $plugin_name => $files ) {
+ foreach ( $files as $file ) {
+ if ( file_exists( get_stylesheet_directory() . '/' . $file ) ) {
+ $theme_file = get_stylesheet_directory() . '/' . $file;
+ } elseif ( file_exists( get_stylesheet_directory() . '/' . WC()->template_path() . $file ) ) {
+ $theme_file = get_stylesheet_directory() . '/' . WC()->template_path() . $file;
+ } elseif ( file_exists( get_template_directory() . '/' . $file ) ) {
+ $theme_file = get_template_directory() . '/' . $file;
+ } elseif ( file_exists( get_template_directory() . '/' . WC()->template_path() . $file ) ) {
+ $theme_file = get_template_directory() . '/' . WC()->template_path() . $file;
+ } else {
+ $theme_file = false;
+ }
+
+ if ( false !== $theme_file ) {
+ $override_data[] = basename( $theme_file );
+ }
+ }
+ }
+ return $override_data;
+ }
+
+ /**
+ * When an admin user logs in, there user agent is tracked in user meta and collected here.
+ *
+ * @return array
+ */
+ private static function get_admin_user_agents() {
+ return array_filter( (array) get_option( 'woocommerce_tracker_ua', array() ) );
+ }
+
+ /**
+ * Get order totals
+ *
+ * @return array
+ */
+ public static function get_order_totals() {
+ global $wpdb;
+
+ $gross_total = $wpdb->get_var(
+ "
+ SELECT
+ SUM( order_meta.meta_value ) AS 'gross_total'
+ FROM {$wpdb->prefix}posts AS orders
+ LEFT JOIN {$wpdb->prefix}postmeta AS order_meta ON order_meta.post_id = orders.ID
+ WHERE order_meta.meta_key = '_order_total'
+ AND orders.post_status in ( 'wc-completed', 'wc-refunded' )
+ GROUP BY order_meta.meta_key
+ "
+ );
+
+ if ( is_null( $gross_total ) ) {
+ $gross_total = 0;
+ }
+
+ $processing_gross_total = $wpdb->get_var(
+ "
+ SELECT
+ SUM( order_meta.meta_value ) AS 'gross_total'
+ FROM {$wpdb->prefix}posts AS orders
+ LEFT JOIN {$wpdb->prefix}postmeta AS order_meta ON order_meta.post_id = orders.ID
+ WHERE order_meta.meta_key = '_order_total'
+ AND orders.post_status = 'wc-processing'
+ GROUP BY order_meta.meta_key
+ "
+ );
+
+ if ( is_null( $processing_gross_total ) ) {
+ $processing_gross_total = 0;
+ }
+
+ return array(
+ 'gross' => $gross_total,
+ 'processing_gross' => $processing_gross_total,
+ );
+ }
+
+ /**
+ * Get last order date
+ *
+ * @return string
+ */
+ private static function get_order_dates() {
+ global $wpdb;
+
+ $min_max = $wpdb->get_row(
+ "
+ SELECT
+ MIN( post_date_gmt ) as 'first', MAX( post_date_gmt ) as 'last'
+ FROM {$wpdb->prefix}posts
+ WHERE post_type = 'shop_order'
+ AND post_status = 'wc-completed'
+ ",
+ ARRAY_A
+ );
+
+ if ( is_null( $min_max ) ) {
+ $min_max = array(
+ 'first' => '-',
+ 'last' => '-',
+ );
+ }
+
+ $processing_min_max = $wpdb->get_row(
+ "
+ SELECT
+ MIN( post_date_gmt ) as 'processing_first', MAX( post_date_gmt ) as 'processing_last'
+ FROM {$wpdb->prefix}posts
+ WHERE post_type = 'shop_order'
+ AND post_status = 'wc-processing'
+ ",
+ ARRAY_A
+ );
+
+ if ( is_null( $processing_min_max ) ) {
+ $processing_min_max = array(
+ 'processing_first' => '-',
+ 'processing_last' => '-',
+ );
+ }
+
+ return array_merge( $min_max, $processing_min_max );
+ }
+
+ /**
+ * Search a specific post for text content.
+ *
+ * @param integer $post_id The id of the post to search.
+ * @param string $text The text to search for.
+ * @return string 'Yes' if post contains $text (otherwise 'No').
+ */
+ public static function post_contains_text( $post_id, $text ) {
+ global $wpdb;
+
+ // Search for the text anywhere in the post.
+ $wildcarded = "%{$text}%";
+
+ $result = $wpdb->get_var(
+ $wpdb->prepare(
+ "
+ SELECT COUNT( * ) FROM {$wpdb->prefix}posts
+ WHERE ID=%d
+ AND {$wpdb->prefix}posts.post_content LIKE %s
+ ",
+ array( $post_id, $wildcarded )
+ )
+ );
+
+ return ( '0' !== $result ) ? 'Yes' : 'No';
+ }
+
+ /**
+ * Get blocks from a woocommerce page.
+ *
+ * @param string $woo_page_name A woocommerce page e.g. `checkout` or `cart`.
+ * @return array Array of blocks as returned by parse_blocks().
+ */
+ private static function get_all_blocks_from_page( $woo_page_name ) {
+ $page_id = wc_get_page_id( $woo_page_name );
+
+ $page = get_post( $page_id );
+ if ( ! $page ) {
+ return array();
+ }
+
+ $blocks = parse_blocks( $page->post_content );
+ if ( ! $blocks ) {
+ return array();
+ }
+
+ return $blocks;
+ }
+
+ /**
+ * Get all instances of the specified block on a specific woo page
+ * (e.g. `cart` or `checkout` page).
+ *
+ * @param string $block_name The name (id) of a block, e.g. `woocommerce/cart`.
+ * @param string $woo_page_name The woo page to search, e.g. `cart`.
+ * @return array Array of blocks as returned by parse_blocks().
+ */
+ private static function get_blocks_from_page( $block_name, $woo_page_name ) {
+ $page_blocks = self::get_all_blocks_from_page( $woo_page_name );
+
+ // Get any instances of the specified block.
+ return array_values(
+ array_filter(
+ $page_blocks,
+ function ( $block ) use ( $block_name ) {
+ return ( $block_name === $block['blockName'] );
+ }
+ )
+ );
+ }
+
+ /**
+ * Get tracker data for a specific block type on a woocommerce page.
+ *
+ * @param string $block_name The name (id) of a block, e.g. `woocommerce/cart`.
+ * @param string $woo_page_name The woo page to search, e.g. `cart`.
+ * @return array Associative array of tracker data with keys:
+ * - page_contains_block
+ * - block_attributes
+ */
+ public static function get_block_tracker_data( $block_name, $woo_page_name ) {
+ $blocks = self::get_blocks_from_page( $block_name, $woo_page_name );
+
+ $block_present = false;
+ $attributes = array();
+ if ( $blocks && count( $blocks ) ) {
+ // Return any customised attributes from the first block.
+ $block_present = true;
+ $attributes = $blocks[0]['attrs'];
+ }
+
+ return array(
+ 'page_contains_block' => $block_present ? 'Yes' : 'No',
+ 'block_attributes' => $attributes,
+ );
+ }
+
+ /**
+ * Get info about the cart & checkout pages.
+ *
+ * @return array
+ */
+ public static function get_cart_checkout_info() {
+ $cart_page_id = wc_get_page_id( 'cart' );
+ $checkout_page_id = wc_get_page_id( 'checkout' );
+
+ $cart_block_data = self::get_block_tracker_data( 'woocommerce/cart', 'cart' );
+ $checkout_block_data = self::get_block_tracker_data( 'woocommerce/checkout', 'checkout' );
+
+ return array(
+ 'cart_page_contains_cart_shortcode' => self::post_contains_text(
+ $cart_page_id,
+ '[woocommerce_cart]'
+ ),
+ 'checkout_page_contains_checkout_shortcode' => self::post_contains_text(
+ $checkout_page_id,
+ '[woocommerce_checkout]'
+ ),
+
+ 'cart_page_contains_cart_block' => $cart_block_data['page_contains_block'],
+ 'cart_block_attributes' => $cart_block_data['block_attributes'],
+ 'checkout_page_contains_checkout_block' => $checkout_block_data['page_contains_block'],
+ 'checkout_block_attributes' => $checkout_block_data['block_attributes'],
+ );
+ }
+}
+
+WC_Tracker::init();
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-validation.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-validation.php
new file mode 100644
index 0000000..c2380d4
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-validation.php
@@ -0,0 +1,201 @@
+ 0 ) {
+ return false;
+ }
+
+ switch ( $country ) {
+ case 'AT':
+ $valid = (bool) preg_match( '/^([0-9]{4})$/', $postcode );
+ break;
+ case 'BA':
+ $valid = (bool) preg_match( '/^([7-8]{1})([0-9]{4})$/', $postcode );
+ break;
+ case 'BE':
+ $valid = (bool) preg_match( '/^([0-9]{4})$/i', $postcode );
+ break;
+ case 'BR':
+ $valid = (bool) preg_match( '/^([0-9]{5})([-])?([0-9]{3})$/', $postcode );
+ break;
+ case 'CH':
+ $valid = (bool) preg_match( '/^([0-9]{4})$/i', $postcode );
+ break;
+ case 'DE':
+ $valid = (bool) preg_match( '/^([0]{1}[1-9]{1}|[1-9]{1}[0-9]{1})[0-9]{3}$/', $postcode );
+ break;
+ case 'ES':
+ case 'FR':
+ case 'IT':
+ $valid = (bool) preg_match( '/^([0-9]{5})$/i', $postcode );
+ break;
+ case 'GB':
+ $valid = self::is_gb_postcode( $postcode );
+ break;
+ case 'HU':
+ $valid = (bool) preg_match( '/^([0-9]{4})$/i', $postcode );
+ break;
+ case 'IE':
+ $valid = (bool) preg_match( '/([AC-FHKNPRTV-Y]\d{2}|D6W)[0-9AC-FHKNPRTV-Y]{4}/', wc_normalize_postcode( $postcode ) );
+ break;
+ case 'IN':
+ $valid = (bool) preg_match( '/^[1-9]{1}[0-9]{2}\s{0,1}[0-9]{3}$/', $postcode );
+ break;
+ case 'JP':
+ $valid = (bool) preg_match( '/^([0-9]{3})([-]?)([0-9]{4})$/', $postcode );
+ break;
+ case 'PT':
+ $valid = (bool) preg_match( '/^([0-9]{4})([-])([0-9]{3})$/', $postcode );
+ break;
+ case 'PR':
+ case 'US':
+ $valid = (bool) preg_match( '/^([0-9]{5})(-[0-9]{4})?$/i', $postcode );
+ break;
+ case 'CA':
+ // CA Postal codes cannot contain D,F,I,O,Q,U and cannot start with W or Z. https://en.wikipedia.org/wiki/Postal_codes_in_Canada#Number_of_possible_postal_codes.
+ $valid = (bool) preg_match( '/^([ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTVWXYZ])([\ ])?(\d[ABCEGHJKLMNPRSTVWXYZ]\d)$/i', $postcode );
+ break;
+ case 'PL':
+ $valid = (bool) preg_match( '/^([0-9]{2})([-])([0-9]{3})$/', $postcode );
+ break;
+ case 'CZ':
+ case 'SK':
+ $valid = (bool) preg_match( '/^([0-9]{3})(\s?)([0-9]{2})$/', $postcode );
+ break;
+ case 'NL':
+ $valid = (bool) preg_match( '/^([1-9][0-9]{3})(\s?)(?!SA|SD|SS)[A-Z]{2}$/i', $postcode );
+ break;
+ case 'SI':
+ $valid = (bool) preg_match( '/^([1-9][0-9]{3})$/', $postcode );
+ break;
+ case 'LI':
+ $valid = (bool) preg_match( '/^(94[8-9][0-9])$/', $postcode );
+ break;
+ default:
+ $valid = true;
+ break;
+ }
+
+ return apply_filters( 'woocommerce_validate_postcode', $valid, $postcode, $country );
+ }
+
+ /**
+ * Check if is a GB postcode.
+ *
+ * @param string $to_check A postcode.
+ * @return bool
+ */
+ public static function is_gb_postcode( $to_check ) {
+
+ // Permitted letters depend upon their position in the postcode.
+ // https://en.wikipedia.org/wiki/Postcodes_in_the_United_Kingdom#Validation.
+ $alpha1 = '[abcdefghijklmnoprstuwyz]'; // Character 1.
+ $alpha2 = '[abcdefghklmnopqrstuvwxy]'; // Character 2.
+ $alpha3 = '[abcdefghjkpstuw]'; // Character 3 == ABCDEFGHJKPSTUW.
+ $alpha4 = '[abehmnprvwxy]'; // Character 4 == ABEHMNPRVWXY.
+ $alpha5 = '[abdefghjlnpqrstuwxyz]'; // Character 5 != CIKMOV.
+
+ $pcexp = array();
+
+ // Expression for postcodes: AN NAA, ANN NAA, AAN NAA, and AANN NAA.
+ $pcexp[0] = '/^(' . $alpha1 . '{1}' . $alpha2 . '{0,1}[0-9]{1,2})([0-9]{1}' . $alpha5 . '{2})$/';
+
+ // Expression for postcodes: ANA NAA.
+ $pcexp[1] = '/^(' . $alpha1 . '{1}[0-9]{1}' . $alpha3 . '{1})([0-9]{1}' . $alpha5 . '{2})$/';
+
+ // Expression for postcodes: AANA NAA.
+ $pcexp[2] = '/^(' . $alpha1 . '{1}' . $alpha2 . '[0-9]{1}' . $alpha4 . ')([0-9]{1}' . $alpha5 . '{2})$/';
+
+ // Exception for the special postcode GIR 0AA.
+ $pcexp[3] = '/^(gir)(0aa)$/';
+
+ // Standard BFPO numbers.
+ $pcexp[4] = '/^(bfpo)([0-9]{1,4})$/';
+
+ // c/o BFPO numbers.
+ $pcexp[5] = '/^(bfpo)(c\/o[0-9]{1,3})$/';
+
+ // Load up the string to check, converting into lowercase and removing spaces.
+ $postcode = strtolower( $to_check );
+ $postcode = str_replace( ' ', '', $postcode );
+
+ // Assume we are not going to find a valid postcode.
+ $valid = false;
+
+ // Check the string against the six types of postcodes.
+ foreach ( $pcexp as $regexp ) {
+ if ( preg_match( $regexp, $postcode, $matches ) ) {
+ // Remember that we have found that the code is valid and break from loop.
+ $valid = true;
+ break;
+ }
+ }
+
+ return $valid;
+ }
+
+ /**
+ * Format the postcode according to the country and length of the postcode.
+ *
+ * @param string $postcode Postcode to format.
+ * @param string $country Country to format the postcode for.
+ * @return string Formatted postcode.
+ */
+ public static function format_postcode( $postcode, $country ) {
+ return wc_format_postcode( $postcode, $country );
+ }
+
+ /**
+ * Format a given phone number.
+ *
+ * @param mixed $tel Phone number to format.
+ * @return string
+ */
+ public static function format_phone( $tel ) {
+ return wc_format_phone_number( $tel );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-webhook.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-webhook.php
new file mode 100644
index 0000000..1d55682
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-wc-webhook.php
@@ -0,0 +1,1073 @@
+ null,
+ 'date_modified' => null,
+ 'status' => 'disabled',
+ 'delivery_url' => '',
+ 'secret' => '',
+ 'name' => '',
+ 'topic' => '',
+ 'hooks' => '',
+ 'resource' => '',
+ 'event' => '',
+ 'failure_count' => 0,
+ 'user_id' => 0,
+ 'api_version' => 3,
+ 'pending_delivery' => false,
+ );
+
+ /**
+ * Load webhook data based on how WC_Webhook is called.
+ *
+ * @param WC_Webhook|int $data Webhook ID or data.
+ * @throws Exception If webhook cannot be read/found and $data is set.
+ */
+ public function __construct( $data = 0 ) {
+ parent::__construct( $data );
+
+ if ( $data instanceof WC_Webhook ) {
+ $this->set_id( absint( $data->get_id() ) );
+ } elseif ( is_numeric( $data ) ) {
+ $this->set_id( $data );
+ }
+
+ $this->data_store = WC_Data_Store::load( 'webhook' );
+
+ // If we have an ID, load the webhook from the DB.
+ if ( $this->get_id() ) {
+ try {
+ $this->data_store->read( $this );
+ } catch ( Exception $e ) {
+ $this->set_id( 0 );
+ $this->set_object_read( true );
+ }
+ } else {
+ $this->set_object_read( true );
+ }
+ }
+
+ /**
+ * Enqueue the hooks associated with the webhook.
+ *
+ * @since 2.2.0
+ */
+ public function enqueue() {
+ $hooks = $this->get_hooks();
+ $url = $this->get_delivery_url();
+
+ if ( is_array( $hooks ) && ! empty( $url ) ) {
+ foreach ( $hooks as $hook ) {
+ add_action( $hook, array( $this, 'process' ) );
+ }
+ }
+ }
+
+ /**
+ * Process the webhook for delivery by verifying that it should be delivered.
+ * and scheduling the delivery (in the background by default, or immediately).
+ *
+ * @since 2.2.0
+ * @param mixed $arg The first argument provided from the associated hooks.
+ * @return mixed $arg Returns the argument in case the webhook was hooked into a filter.
+ */
+ public function process( $arg ) {
+
+ // Verify that webhook should be processed for delivery.
+ if ( ! $this->should_deliver( $arg ) ) {
+ return;
+ }
+
+ // Mark this $arg as processed to ensure it doesn't get processed again within the current request.
+ $this->processed[] = $arg;
+
+ /**
+ * Process webhook delivery.
+ *
+ * @since 3.3.0
+ * @hooked wc_webhook_process_delivery - 10
+ */
+ do_action( 'woocommerce_webhook_process_delivery', $this, $arg );
+
+ return $arg;
+ }
+
+ /**
+ * Helper to check if the webhook should be delivered, as some hooks.
+ * (like `wp_trash_post`) will fire for every post type, not just ours.
+ *
+ * @since 2.2.0
+ * @param mixed $arg First hook argument.
+ * @return bool True if webhook should be delivered, false otherwise.
+ */
+ private function should_deliver( $arg ) {
+ $should_deliver = $this->is_active() && $this->is_valid_topic() && $this->is_valid_action( $arg ) && $this->is_valid_resource( $arg ) && ! $this->is_already_processed( $arg );
+
+ /**
+ * Let other plugins intercept deliver for some messages queue like rabbit/zeromq.
+ *
+ * @param bool $should_deliver True if the webhook should be sent, or false to not send it.
+ * @param WC_Webhook $this The current webhook class.
+ * @param mixed $arg First hook argument.
+ */
+ return apply_filters( 'woocommerce_webhook_should_deliver', $should_deliver, $this, $arg );
+ }
+
+ /**
+ * Returns if webhook is active.
+ *
+ * @since 3.6.0
+ * @return bool True if validation passes.
+ */
+ private function is_active() {
+ return 'active' === $this->get_status();
+ }
+
+ /**
+ * Returns if topic is valid.
+ *
+ * @since 3.6.0
+ * @return bool True if validation passes.
+ */
+ private function is_valid_topic() {
+ return wc_is_webhook_valid_topic( $this->get_topic() );
+ }
+
+ /**
+ * Validates the criteria for certain actions.
+ *
+ * @since 3.6.0
+ * @param mixed $arg First hook argument.
+ * @return bool True if validation passes.
+ */
+ private function is_valid_action( $arg ) {
+ $current_action = current_action();
+ $return = true;
+
+ switch ( $current_action ) {
+ case 'delete_post':
+ case 'wp_trash_post':
+ case 'untrashed_post':
+ $return = $this->is_valid_post_action( $arg );
+ break;
+ case 'delete_user':
+ $return = $this->is_valid_user_action( $arg );
+ break;
+ }
+
+ if ( 0 === strpos( $current_action, 'woocommerce_process_shop' ) || 0 === strpos( $current_action, 'woocommerce_process_product' ) ) {
+ $return = $this->is_valid_processing_action( $arg );
+ }
+
+ return $return;
+ }
+
+ /**
+ * Validates post actions.
+ *
+ * @since 3.6.0
+ * @param mixed $arg First hook argument.
+ * @return bool True if validation passes.
+ */
+ private function is_valid_post_action( $arg ) {
+ // Only deliver deleted/restored event for coupons, orders, and products.
+ if ( isset( $GLOBALS['post_type'] ) && ! in_array( $GLOBALS['post_type'], array( 'shop_coupon', 'shop_order', 'product' ), true ) ) {
+ return false;
+ }
+
+ // Check if is delivering for the correct resource.
+ if ( isset( $GLOBALS['post_type'] ) && str_replace( 'shop_', '', $GLOBALS['post_type'] ) !== $this->get_resource() ) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Validates user actions.
+ *
+ * @since 3.6.0
+ * @param mixed $arg First hook argument.
+ * @return bool True if validation passes.
+ */
+ private function is_valid_user_action( $arg ) {
+ $user = get_userdata( absint( $arg ) );
+
+ // Only deliver deleted customer event for users with customer role.
+ if ( ! $user || ! in_array( 'customer', (array) $user->roles, true ) ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Validates WC processing actions.
+ *
+ * @since 3.6.0
+ * @param mixed $arg First hook argument.
+ * @return bool True if validation passes.
+ */
+ private function is_valid_processing_action( $arg ) {
+ // The `woocommerce_process_shop_*` and `woocommerce_process_product_*` hooks
+ // fire for create and update of products and orders, so check the post
+ // creation date to determine the actual event.
+ $resource = get_post( absint( $arg ) );
+
+ // Drafts don't have post_date_gmt so calculate it here.
+ $gmt_date = get_gmt_from_date( $resource->post_date );
+
+ // A resource is considered created when the hook is executed within 10 seconds of the post creation date.
+ $resource_created = ( ( time() - 10 ) <= strtotime( $gmt_date ) );
+
+ if ( 'created' === $this->get_event() && ! $resource_created ) {
+ return false;
+ } elseif ( 'updated' === $this->get_event() && $resource_created ) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Checks the resource for this webhook is valid e.g. valid post status.
+ *
+ * @since 3.6.0
+ * @param mixed $arg First hook argument.
+ * @return bool True if validation passes.
+ */
+ private function is_valid_resource( $arg ) {
+ $resource = $this->get_resource();
+
+ if ( in_array( $resource, array( 'order', 'product', 'coupon' ), true ) ) {
+ $status = get_post_status( absint( $arg ) );
+
+ // Ignore auto drafts for all resources.
+ if ( in_array( $status, array( 'auto-draft', 'new' ), true ) ) {
+ return false;
+ }
+
+ // Ignore standard drafts for orders.
+ if ( 'order' === $resource && 'draft' === $status ) {
+ return false;
+ }
+
+ // Check registered order types for order types args.
+ if ( 'order' === $resource && ! in_array( get_post_type( absint( $arg ) ), wc_get_order_types( 'order-webhooks' ), true ) ) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Checks if the specified resource has already been queued for delivery within the current request.
+ *
+ * Helps avoid duplication of data being sent for topics that have more than one hook defined.
+ *
+ * @param mixed $arg First hook argument.
+ *
+ * @return bool
+ */
+ protected function is_already_processed( $arg ) {
+ return false !== array_search( $arg, $this->processed, true );
+ }
+
+ /**
+ * Deliver the webhook payload using wp_safe_remote_request().
+ *
+ * @since 2.2.0
+ * @param mixed $arg First hook argument.
+ */
+ public function deliver( $arg ) {
+ $start_time = microtime( true );
+ $payload = $this->build_payload( $arg );
+
+ // Setup request args.
+ $http_args = array(
+ 'method' => 'POST',
+ 'timeout' => MINUTE_IN_SECONDS,
+ 'redirection' => 0,
+ 'httpversion' => '1.0',
+ 'blocking' => true,
+ 'user-agent' => sprintf( 'WooCommerce/%s Hookshot (WordPress/%s)', Constants::get_constant( 'WC_VERSION' ), $GLOBALS['wp_version'] ),
+ 'body' => trim( wp_json_encode( $payload ) ),
+ 'headers' => array(
+ 'Content-Type' => 'application/json',
+ ),
+ 'cookies' => array(),
+ );
+
+ $http_args = apply_filters( 'woocommerce_webhook_http_args', $http_args, $arg, $this->get_id() );
+
+ // Add custom headers.
+ $delivery_id = $this->get_new_delivery_id();
+ $http_args['headers']['X-WC-Webhook-Source'] = home_url( '/' ); // Since 2.6.0.
+ $http_args['headers']['X-WC-Webhook-Topic'] = $this->get_topic();
+ $http_args['headers']['X-WC-Webhook-Resource'] = $this->get_resource();
+ $http_args['headers']['X-WC-Webhook-Event'] = $this->get_event();
+ $http_args['headers']['X-WC-Webhook-Signature'] = $this->generate_signature( $http_args['body'] );
+ $http_args['headers']['X-WC-Webhook-ID'] = $this->get_id();
+ $http_args['headers']['X-WC-Webhook-Delivery-ID'] = $delivery_id;
+
+ // Webhook away!
+ $response = wp_safe_remote_request( $this->get_delivery_url(), $http_args );
+
+ $duration = NumberUtil::round( microtime( true ) - $start_time, 5 );
+
+ $this->log_delivery( $delivery_id, $http_args, $response, $duration );
+
+ do_action( 'woocommerce_webhook_delivery', $http_args, $response, $duration, $arg, $this->get_id() );
+ }
+
+ /**
+ * Get Legacy API payload.
+ *
+ * @since 3.0.0
+ * @param string $resource Resource type.
+ * @param int $resource_id Resource ID.
+ * @param string $event Event type.
+ * @return array
+ */
+ private function get_legacy_api_payload( $resource, $resource_id, $event ) {
+ // Include & load API classes.
+ WC()->api->includes();
+ WC()->api->register_resources( new WC_API_Server( '/' ) );
+
+ switch ( $resource ) {
+ case 'coupon':
+ $payload = WC()->api->WC_API_Coupons->get_coupon( $resource_id );
+ break;
+
+ case 'customer':
+ $payload = WC()->api->WC_API_Customers->get_customer( $resource_id );
+ break;
+
+ case 'order':
+ $payload = WC()->api->WC_API_Orders->get_order( $resource_id, null, apply_filters( 'woocommerce_webhook_order_payload_filters', array() ) );
+ break;
+
+ case 'product':
+ // Bulk and quick edit action hooks return a product object instead of an ID.
+ if ( 'updated' === $event && is_a( $resource_id, 'WC_Product' ) ) {
+ $resource_id = $resource_id->get_id();
+ }
+ $payload = WC()->api->WC_API_Products->get_product( $resource_id );
+ break;
+
+ // Custom topics include the first hook argument.
+ case 'action':
+ $payload = array(
+ 'action' => current( $this->get_hooks() ),
+ 'arg' => $resource_id,
+ );
+ break;
+
+ default:
+ $payload = array();
+ break;
+ }
+
+ return $payload;
+ }
+
+ /**
+ * Get WP API integration payload.
+ *
+ * @since 3.0.0
+ * @param string $resource Resource type.
+ * @param int $resource_id Resource ID.
+ * @param string $event Event type.
+ * @return array
+ */
+ private function get_wp_api_payload( $resource, $resource_id, $event ) {
+ switch ( $resource ) {
+ case 'coupon':
+ case 'customer':
+ case 'order':
+ case 'product':
+ // Bulk and quick edit action hooks return a product object instead of an ID.
+ if ( 'product' === $resource && 'updated' === $event && is_a( $resource_id, 'WC_Product' ) ) {
+ $resource_id = $resource_id->get_id();
+ }
+
+ $version = str_replace( 'wp_api_', '', $this->get_api_version() );
+ $payload = wc()->api->get_endpoint_data( "/wc/{$version}/{$resource}s/{$resource_id}" );
+ break;
+
+ // Custom topics include the first hook argument.
+ case 'action':
+ $payload = array(
+ 'action' => current( $this->get_hooks() ),
+ 'arg' => $resource_id,
+ );
+ break;
+
+ default:
+ $payload = array();
+ break;
+ }
+
+ return $payload;
+ }
+
+ /**
+ * Build the payload data for the webhook.
+ *
+ * @since 2.2.0
+ * @param mixed $resource_id First hook argument, typically the resource ID.
+ * @return mixed Payload data.
+ */
+ public function build_payload( $resource_id ) {
+ // Build the payload with the same user context as the user who created
+ // the webhook -- this avoids permission errors as background processing
+ // runs with no user context.
+ $current_user = get_current_user_id();
+ wp_set_current_user( $this->get_user_id() );
+
+ $resource = $this->get_resource();
+ $event = $this->get_event();
+
+ // If a resource has been deleted, just include the ID.
+ if ( 'deleted' === $event ) {
+ $payload = array(
+ 'id' => $resource_id,
+ );
+ } else {
+ if ( in_array( $this->get_api_version(), wc_get_webhook_rest_api_versions(), true ) ) {
+ $payload = $this->get_wp_api_payload( $resource, $resource_id, $event );
+ } else {
+ $payload = $this->get_legacy_api_payload( $resource, $resource_id, $event );
+ }
+ }
+
+ // Restore the current user.
+ wp_set_current_user( $current_user );
+
+ return apply_filters( 'woocommerce_webhook_payload', $payload, $resource, $resource_id, $this->get_id() );
+ }
+
+ /**
+ * Generate a base64-encoded HMAC-SHA256 signature of the payload body so the
+ * recipient can verify the authenticity of the webhook. Note that the signature
+ * is calculated after the body has already been encoded (JSON by default).
+ *
+ * @since 2.2.0
+ * @param string $payload Payload data to hash.
+ * @return string
+ */
+ public function generate_signature( $payload ) {
+ $hash_algo = apply_filters( 'woocommerce_webhook_hash_algorithm', 'sha256', $payload, $this->get_id() );
+
+ // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
+ return base64_encode( hash_hmac( $hash_algo, $payload, wp_specialchars_decode( $this->get_secret(), ENT_QUOTES ), true ) );
+ }
+
+ /**
+ * Generate a new unique hash as a delivery id based on current time and wehbook id.
+ * Return the hash for inclusion in the webhook request.
+ *
+ * @since 2.2.0
+ * @return string
+ */
+ public function get_new_delivery_id() {
+ // Since we no longer use comments to store delivery logs, we generate a unique hash instead based on current time and webhook ID.
+ return wp_hash( $this->get_id() . strtotime( 'now' ) );
+ }
+
+ /**
+ * Log the delivery request/response.
+ *
+ * @since 2.2.0
+ * @param string $delivery_id Previously created hash.
+ * @param array $request Request data.
+ * @param array|WP_Error $response Response data.
+ * @param float $duration Request duration.
+ */
+ public function log_delivery( $delivery_id, $request, $response, $duration ) {
+ $logger = wc_get_logger();
+ $message = array(
+ 'Webhook Delivery' => array(
+ 'Delivery ID' => $delivery_id,
+ 'Date' => date_i18n( __( 'M j, Y @ G:i', 'woocommerce' ), strtotime( 'now' ), true ),
+ 'URL' => $this->get_delivery_url(),
+ 'Duration' => $duration,
+ 'Request' => array(
+ 'Method' => $request['method'],
+ 'Headers' => array_merge(
+ array(
+ 'User-Agent' => $request['user-agent'],
+ ),
+ $request['headers']
+ ),
+ ),
+ 'Body' => wp_slash( $request['body'] ),
+ ),
+ );
+
+ // Parse response.
+ if ( is_wp_error( $response ) ) {
+ $response_code = $response->get_error_code();
+ $response_message = $response->get_error_message();
+ $response_headers = array();
+ $response_body = '';
+ } else {
+ $response_code = wp_remote_retrieve_response_code( $response );
+ $response_message = wp_remote_retrieve_response_message( $response );
+ $response_headers = wp_remote_retrieve_headers( $response );
+ $response_body = wp_remote_retrieve_body( $response );
+ }
+
+ $message['Webhook Delivery']['Response'] = array(
+ 'Code' => $response_code,
+ 'Message' => $response_message,
+ 'Headers' => $response_headers,
+ 'Body' => $response_body,
+ );
+
+ if ( ! Constants::is_true( 'WP_DEBUG' ) ) {
+ $message['Webhook Delivery']['Body'] = 'Webhook body is not logged unless WP_DEBUG mode is turned on. This is to avoid the storing of personal data in the logs.';
+ $message['Webhook Delivery']['Response']['Body'] = 'Webhook body is not logged unless WP_DEBUG mode is turned on. This is to avoid the storing of personal data in the logs.';
+ }
+
+ $logger->info(
+ wc_print_r( $message, true ),
+ array(
+ 'source' => 'webhooks-delivery',
+ )
+ );
+
+ // Track failures.
+ // Check for a success, which is a 2xx, 301 or 302 Response Code.
+ if ( intval( $response_code ) >= 200 && intval( $response_code ) < 303 ) {
+ $this->set_failure_count( 0 );
+ $this->save();
+ } else {
+ $this->failed_delivery();
+ }
+ }
+
+ /**
+ * Track consecutive delivery failures and automatically disable the webhook.
+ * if more than 5 consecutive failures occur. A failure is defined as a.
+ * non-2xx response.
+ *
+ * @since 2.2.0
+ */
+ private function failed_delivery() {
+ $failures = $this->get_failure_count();
+
+ if ( $failures > apply_filters( 'woocommerce_max_webhook_delivery_failures', 5 ) ) {
+ $this->set_status( 'disabled' );
+
+ do_action( 'woocommerce_webhook_disabled_due_delivery_failures', $this->get_id() );
+ } else {
+ $this->set_failure_count( ++$failures );
+ }
+
+ $this->save();
+ }
+
+ /**
+ * Get the delivery logs for this webhook.
+ *
+ * @since 3.3.0
+ * @return string
+ */
+ public function get_delivery_logs() {
+ return esc_url( add_query_arg( 'log_file', wc_get_log_file_name( 'webhooks-delivery' ), admin_url( 'admin.php?page=wc-status&tab=logs' ) ) );
+ }
+
+ /**
+ * Get the delivery log specified by the ID. The delivery log includes:
+ *
+ * + duration
+ * + summary
+ * + request method/url
+ * + request headers/body
+ * + response code/message/headers/body
+ *
+ * @since 2.2
+ * @deprecated 3.3.0
+ * @param int $delivery_id Delivery ID.
+ * @return void
+ */
+ public function get_delivery_log( $delivery_id ) {
+ wc_deprecated_function( 'WC_Webhook::get_delivery_log', '3.3' );
+ }
+
+ /**
+ * Send a test ping to the delivery URL, sent when the webhook is first created.
+ *
+ * @since 2.2.0
+ * @return bool|WP_Error
+ */
+ public function deliver_ping() {
+ $args = array(
+ 'user-agent' => sprintf( 'WooCommerce/%s Hookshot (WordPress/%s)', Constants::get_constant( 'WC_VERSION' ), $GLOBALS['wp_version'] ),
+ 'body' => 'webhook_id=' . $this->get_id(),
+ );
+
+ $test = wp_safe_remote_post( $this->get_delivery_url(), $args );
+ $response_code = wp_remote_retrieve_response_code( $test );
+
+ if ( is_wp_error( $test ) ) {
+ /* translators: error message */
+ return new WP_Error( 'error', sprintf( __( 'Error: Delivery URL cannot be reached: %s', 'woocommerce' ), $test->get_error_message() ) );
+ }
+
+ if ( 200 !== $response_code ) {
+ /* translators: error message */
+ return new WP_Error( 'error', sprintf( __( 'Error: Delivery URL returned response code: %s', 'woocommerce' ), absint( $response_code ) ) );
+ }
+
+ $this->set_pending_delivery( false );
+ $this->save();
+
+ return true;
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Getters
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Get the friendly name for the webhook.
+ *
+ * @since 2.2.0
+ * @param string $context What the value is for.
+ * Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_name( $context = 'view' ) {
+ return apply_filters( 'woocommerce_webhook_name', $this->get_prop( 'name', $context ), $this->get_id() );
+ }
+
+ /**
+ * Get the webhook status.
+ *
+ * - 'active' - delivers payload.
+ * - 'paused' - does not deliver payload, paused by admin.
+ * - 'disabled' - does not delivery payload, paused automatically due to consecutive failures.
+ *
+ * @since 2.2.0
+ * @param string $context What the value is for.
+ * Valid values are 'view' and 'edit'.
+ * @return string status
+ */
+ public function get_status( $context = 'view' ) {
+ return apply_filters( 'woocommerce_webhook_status', $this->get_prop( 'status', $context ), $this->get_id() );
+ }
+
+ /**
+ * Get webhook created date.
+ *
+ * @since 3.2.0
+ * @param string $context What the value is for.
+ * Valid values are 'view' and 'edit'.
+ * @return WC_DateTime|null Object if the date is set or null if there is no date.
+ */
+ public function get_date_created( $context = 'view' ) {
+ return $this->get_prop( 'date_created', $context );
+ }
+
+ /**
+ * Get webhook modified date.
+ *
+ * @since 3.2.0
+ * @param string $context What the value is for.
+ * Valid values are 'view' and 'edit'.
+ * @return WC_DateTime|null Object if the date is set or null if there is no date.
+ */
+ public function get_date_modified( $context = 'view' ) {
+ return $this->get_prop( 'date_modified', $context );
+ }
+
+ /**
+ * Get the secret used for generating the HMAC-SHA256 signature.
+ *
+ * @since 2.2.0
+ * @param string $context What the value is for.
+ * Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_secret( $context = 'view' ) {
+ return apply_filters( 'woocommerce_webhook_secret', $this->get_prop( 'secret', $context ), $this->get_id() );
+ }
+
+ /**
+ * Get the webhook topic, e.g. `order.created`.
+ *
+ * @since 2.2.0
+ * @param string $context What the value is for.
+ * Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_topic( $context = 'view' ) {
+ return apply_filters( 'woocommerce_webhook_topic', $this->get_prop( 'topic', $context ), $this->get_id() );
+ }
+
+ /**
+ * Get the delivery URL.
+ *
+ * @since 2.2.0
+ * @param string $context What the value is for.
+ * Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_delivery_url( $context = 'view' ) {
+ return apply_filters( 'woocommerce_webhook_delivery_url', $this->get_prop( 'delivery_url', $context ), $this->get_id() );
+ }
+
+ /**
+ * Get the user ID for this webhook.
+ *
+ * @since 2.2.0
+ * @param string $context What the value is for.
+ * Valid values are 'view' and 'edit'.
+ * @return int
+ */
+ public function get_user_id( $context = 'view' ) {
+ return $this->get_prop( 'user_id', $context );
+ }
+
+ /**
+ * API version.
+ *
+ * @since 3.0.0
+ * @param string $context What the value is for.
+ * Valid values are 'view' and 'edit'.
+ * @return string
+ */
+ public function get_api_version( $context = 'view' ) {
+ $version = $this->get_prop( 'api_version', $context );
+
+ return 0 < $version ? 'wp_api_v' . $version : 'legacy_v3';
+ }
+
+ /**
+ * Get the failure count.
+ *
+ * @since 2.2.0
+ * @param string $context What the value is for.
+ * Valid values are 'view' and 'edit'.
+ * @return int
+ */
+ public function get_failure_count( $context = 'view' ) {
+ return $this->get_prop( 'failure_count', $context );
+ }
+
+ /**
+ * Get pending delivery.
+ *
+ * @since 3.2.0
+ * @param string $context What the value is for.
+ * Valid values are 'view' and 'edit'.
+ * @return bool
+ */
+ public function get_pending_delivery( $context = 'view' ) {
+ return $this->get_prop( 'pending_delivery', $context );
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Setters
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Set webhook name.
+ *
+ * @since 3.2.0
+ * @param string $name Webhook name.
+ */
+ public function set_name( $name ) {
+ $this->set_prop( 'name', $name );
+ }
+
+ /**
+ * Set webhook created date.
+ *
+ * @since 3.2.0
+ * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime.
+ * If the DateTime string has no timezone or offset,
+ * WordPress site timezone will be assumed.
+ * Null if their is no date.
+ */
+ public function set_date_created( $date = null ) {
+ $this->set_date_prop( 'date_created', $date );
+ }
+
+ /**
+ * Set webhook modified date.
+ *
+ * @since 3.2.0
+ * @param string|integer|null $date UTC timestamp, or ISO 8601 DateTime.
+ * If the DateTime string has no timezone or offset,
+ * WordPress site timezone will be assumed.
+ * Null if their is no date.
+ */
+ public function set_date_modified( $date = null ) {
+ $this->set_date_prop( 'date_modified', $date );
+ }
+
+ /**
+ * Set status.
+ *
+ * @since 3.2.0
+ * @param string $status Status.
+ */
+ public function set_status( $status ) {
+ if ( ! array_key_exists( $status, wc_get_webhook_statuses() ) ) {
+ $status = 'disabled';
+ }
+
+ $this->set_prop( 'status', $status );
+ }
+
+ /**
+ * Set the secret used for generating the HMAC-SHA256 signature.
+ *
+ * @since 2.2.0
+ * @param string $secret Secret.
+ */
+ public function set_secret( $secret ) {
+ $this->set_prop( 'secret', $secret );
+ }
+
+ /**
+ * Set the webhook topic and associated hooks.
+ * The topic resource & event are also saved separately.
+ *
+ * @since 2.2.0
+ * @param string $topic Webhook topic.
+ */
+ public function set_topic( $topic ) {
+ $topic = wc_clean( $topic );
+
+ if ( ! wc_is_webhook_valid_topic( $topic ) ) {
+ $topic = '';
+ }
+
+ $this->set_prop( 'topic', $topic );
+ }
+
+ /**
+ * Set the delivery URL.
+ *
+ * @since 2.2.0
+ * @param string $url Delivery URL.
+ */
+ public function set_delivery_url( $url ) {
+ $this->set_prop( 'delivery_url', esc_url_raw( $url, array( 'http', 'https' ) ) );
+ }
+
+ /**
+ * Set user ID.
+ *
+ * @since 3.2.0
+ * @param int $user_id User ID.
+ */
+ public function set_user_id( $user_id ) {
+ $this->set_prop( 'user_id', (int) $user_id );
+ }
+
+ /**
+ * Set API version.
+ *
+ * @since 3.0.0
+ * @param int|string $version REST API version.
+ */
+ public function set_api_version( $version ) {
+ if ( ! is_numeric( $version ) ) {
+ $version = $this->data_store->get_api_version_number( $version );
+ }
+
+ $this->set_prop( 'api_version', (int) $version );
+ }
+
+ /**
+ * Set pending delivery.
+ *
+ * @since 3.2.0
+ * @param bool $pending_delivery Set true if is pending for delivery.
+ */
+ public function set_pending_delivery( $pending_delivery ) {
+ $this->set_prop( 'pending_delivery', (bool) $pending_delivery );
+ }
+
+ /**
+ * Set failure count.
+ *
+ * @since 3.2.0
+ * @param bool $failure_count Total of failures.
+ */
+ public function set_failure_count( $failure_count ) {
+ $this->set_prop( 'failure_count', intval( $failure_count ) );
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Non-CRUD Getters
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Get the associated hook names for a topic.
+ *
+ * @since 2.2.0
+ * @param string $topic Topic name.
+ * @return array
+ */
+ private function get_topic_hooks( $topic ) {
+ $topic_hooks = array(
+ 'coupon.created' => array(
+ 'woocommerce_process_shop_coupon_meta',
+ 'woocommerce_new_coupon',
+ ),
+ 'coupon.updated' => array(
+ 'woocommerce_process_shop_coupon_meta',
+ 'woocommerce_update_coupon',
+ ),
+ 'coupon.deleted' => array(
+ 'wp_trash_post',
+ ),
+ 'coupon.restored' => array(
+ 'untrashed_post',
+ ),
+ 'customer.created' => array(
+ 'user_register',
+ 'woocommerce_created_customer',
+ 'woocommerce_new_customer',
+ ),
+ 'customer.updated' => array(
+ 'profile_update',
+ 'woocommerce_update_customer',
+ ),
+ 'customer.deleted' => array(
+ 'delete_user',
+ ),
+ 'order.created' => array(
+ 'woocommerce_new_order',
+ ),
+ 'order.updated' => array(
+ 'woocommerce_update_order',
+ 'woocommerce_order_refunded',
+ ),
+ 'order.deleted' => array(
+ 'wp_trash_post',
+ ),
+ 'order.restored' => array(
+ 'untrashed_post',
+ ),
+ 'product.created' => array(
+ 'woocommerce_process_product_meta',
+ 'woocommerce_new_product',
+ 'woocommerce_new_product_variation',
+ ),
+ 'product.updated' => array(
+ 'woocommerce_process_product_meta',
+ 'woocommerce_update_product',
+ 'woocommerce_update_product_variation',
+ ),
+ 'product.deleted' => array(
+ 'wp_trash_post',
+ ),
+ 'product.restored' => array(
+ 'untrashed_post',
+ ),
+ );
+
+ $topic_hooks = apply_filters( 'woocommerce_webhook_topic_hooks', $topic_hooks, $this );
+
+ return isset( $topic_hooks[ $topic ] ) ? $topic_hooks[ $topic ] : array();
+ }
+
+ /**
+ * Get the hook names for the webhook.
+ *
+ * @since 2.2.0
+ * @return array
+ */
+ public function get_hooks() {
+ if ( 'action' === $this->get_resource() ) {
+ $hooks = array( $this->get_event() );
+ } else {
+ $hooks = $this->get_topic_hooks( $this->get_topic() );
+ }
+
+ return apply_filters( 'woocommerce_webhook_hooks', $hooks, $this->get_id() );
+ }
+
+ /**
+ * Get the resource for the webhook, e.g. `order`.
+ *
+ * @since 2.2.0
+ * @return string
+ */
+ public function get_resource() {
+ $topic = explode( '.', $this->get_topic() );
+
+ return apply_filters( 'woocommerce_webhook_resource', $topic[0], $this->get_id() );
+ }
+
+ /**
+ * Get the event for the webhook, e.g. `created`.
+ *
+ * @since 2.2.0
+ * @return string
+ */
+ public function get_event() {
+ $topic = explode( '.', $this->get_topic() );
+
+ return apply_filters( 'woocommerce_webhook_event', isset( $topic[1] ) ? $topic[1] : '', $this->get_id() );
+ }
+
+ /**
+ * Get the webhook i18n status.
+ *
+ * @return string
+ */
+ public function get_i18n_status() {
+ $status = $this->get_status();
+ $statuses = wc_get_webhook_statuses();
+
+ return isset( $statuses[ $status ] ) ? $statuses[ $status ] : $status;
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-woocommerce.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-woocommerce.php
new file mode 100644
index 0000000..c5313fd
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/class-woocommerce.php
@@ -0,0 +1,974 @@
+$key();
+ }
+ }
+
+ /**
+ * WooCommerce Constructor.
+ */
+ public function __construct() {
+ $this->define_constants();
+ $this->define_tables();
+ $this->includes();
+ $this->init_hooks();
+ }
+
+ /**
+ * When WP has loaded all plugins, trigger the `woocommerce_loaded` hook.
+ *
+ * This ensures `woocommerce_loaded` is called only after all other plugins
+ * are loaded, to avoid issues caused by plugin directory naming changing
+ * the load order. See #21524 for details.
+ *
+ * @since 3.6.0
+ */
+ public function on_plugins_loaded() {
+ do_action( 'woocommerce_loaded' );
+ }
+
+ /**
+ * Hook into actions and filters.
+ *
+ * @since 2.3
+ */
+ private function init_hooks() {
+ register_activation_hook( WC_PLUGIN_FILE, array( 'WC_Install', 'install' ) );
+ register_shutdown_function( array( $this, 'log_errors' ) );
+
+ add_action( 'plugins_loaded', array( $this, 'on_plugins_loaded' ), -1 );
+ add_action( 'admin_notices', array( $this, 'build_dependencies_notice' ) );
+ add_action( 'after_setup_theme', array( $this, 'setup_environment' ) );
+ add_action( 'after_setup_theme', array( $this, 'include_template_functions' ), 11 );
+ add_action( 'init', array( $this, 'init' ), 0 );
+ add_action( 'init', array( 'WC_Shortcodes', 'init' ) );
+ add_action( 'init', array( 'WC_Emails', 'init_transactional_emails' ) );
+ add_action( 'init', array( $this, 'add_image_sizes' ) );
+ add_action( 'init', array( $this, 'load_rest_api' ) );
+ add_action( 'switch_blog', array( $this, 'wpdb_table_fix' ), 0 );
+ add_action( 'activated_plugin', array( $this, 'activated_plugin' ) );
+ add_action( 'deactivated_plugin', array( $this, 'deactivated_plugin' ) );
+ }
+
+ /**
+ * Ensures fatal errors are logged so they can be picked up in the status report.
+ *
+ * @since 3.2.0
+ */
+ public function log_errors() {
+ $error = error_get_last();
+ if ( $error && in_array( $error['type'], array( E_ERROR, E_PARSE, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR ), true ) ) {
+ $logger = wc_get_logger();
+ $logger->critical(
+ /* translators: 1: error message 2: file name and path 3: line number */
+ sprintf( __( '%1$s in %2$s on line %3$s', 'woocommerce' ), $error['message'], $error['file'], $error['line'] ) . PHP_EOL,
+ array(
+ 'source' => 'fatal-errors',
+ )
+ );
+ do_action( 'woocommerce_shutdown_error', $error );
+ }
+ }
+
+ /**
+ * Define WC Constants.
+ */
+ private function define_constants() {
+ $upload_dir = wp_upload_dir( null, false );
+
+ $this->define( 'WC_ABSPATH', dirname( WC_PLUGIN_FILE ) . '/' );
+ $this->define( 'WC_PLUGIN_BASENAME', plugin_basename( WC_PLUGIN_FILE ) );
+ $this->define( 'WC_VERSION', $this->version );
+ $this->define( 'WOOCOMMERCE_VERSION', $this->version );
+ $this->define( 'WC_ROUNDING_PRECISION', 6 );
+ $this->define( 'WC_DISCOUNT_ROUNDING_MODE', 2 );
+ $this->define( 'WC_TAX_ROUNDING_MODE', 'yes' === get_option( 'woocommerce_prices_include_tax', 'no' ) ? 2 : 1 );
+ $this->define( 'WC_DELIMITER', '|' );
+ $this->define( 'WC_LOG_DIR', $upload_dir['basedir'] . '/wc-logs/' );
+ $this->define( 'WC_SESSION_CACHE_GROUP', 'wc_session_id' );
+ $this->define( 'WC_TEMPLATE_DEBUG_MODE', false );
+ $this->define( 'WC_NOTICE_MIN_PHP_VERSION', '7.2' );
+ $this->define( 'WC_NOTICE_MIN_WP_VERSION', '5.2' );
+ $this->define( 'WC_PHP_MIN_REQUIREMENTS_NOTICE', 'wp_php_min_requirements_' . WC_NOTICE_MIN_PHP_VERSION . '_' . WC_NOTICE_MIN_WP_VERSION );
+ }
+
+ /**
+ * Register custom tables within $wpdb object.
+ */
+ private function define_tables() {
+ global $wpdb;
+
+ // List of tables without prefixes.
+ $tables = array(
+ 'payment_tokenmeta' => 'woocommerce_payment_tokenmeta',
+ 'order_itemmeta' => 'woocommerce_order_itemmeta',
+ 'wc_product_meta_lookup' => 'wc_product_meta_lookup',
+ 'wc_tax_rate_classes' => 'wc_tax_rate_classes',
+ 'wc_reserved_stock' => 'wc_reserved_stock',
+ );
+
+ foreach ( $tables as $name => $table ) {
+ $wpdb->$name = $wpdb->prefix . $table;
+ $wpdb->tables[] = $table;
+ }
+ }
+
+ /**
+ * Define constant if not already set.
+ *
+ * @param string $name Constant name.
+ * @param string|bool $value Constant value.
+ */
+ private function define( $name, $value ) {
+ if ( ! defined( $name ) ) {
+ define( $name, $value );
+ }
+ }
+
+ /**
+ * Returns true if the request is a non-legacy REST API request.
+ *
+ * Legacy REST requests should still run some extra code for backwards compatibility.
+ *
+ * @todo: replace this function once core WP function is available: https://core.trac.wordpress.org/ticket/42061.
+ *
+ * @return bool
+ */
+ public function is_rest_api_request() {
+ if ( empty( $_SERVER['REQUEST_URI'] ) ) {
+ return false;
+ }
+
+ $rest_prefix = trailingslashit( rest_get_url_prefix() );
+ $is_rest_api_request = ( false !== strpos( $_SERVER['REQUEST_URI'], $rest_prefix ) ); // phpcs:disable WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
+
+ return apply_filters( 'woocommerce_is_rest_api_request', $is_rest_api_request );
+ }
+
+ /**
+ * Load REST API.
+ */
+ public function load_rest_api() {
+ \Automattic\WooCommerce\RestApi\Server::instance()->init();
+ }
+
+ /**
+ * What type of request is this?
+ *
+ * @param string $type admin, ajax, cron or frontend.
+ * @return bool
+ */
+ private function is_request( $type ) {
+ switch ( $type ) {
+ case 'admin':
+ return is_admin();
+ case 'ajax':
+ return defined( 'DOING_AJAX' );
+ case 'cron':
+ return defined( 'DOING_CRON' );
+ case 'frontend':
+ return ( ! is_admin() || defined( 'DOING_AJAX' ) ) && ! defined( 'DOING_CRON' ) && ! $this->is_rest_api_request();
+ }
+ }
+
+ /**
+ * Include required core files used in admin and on the frontend.
+ */
+ public function includes() {
+ /**
+ * Class autoloader.
+ */
+ include_once WC_ABSPATH . 'includes/class-wc-autoloader.php';
+
+ /**
+ * Interfaces.
+ */
+ include_once WC_ABSPATH . 'includes/interfaces/class-wc-abstract-order-data-store-interface.php';
+ include_once WC_ABSPATH . 'includes/interfaces/class-wc-coupon-data-store-interface.php';
+ include_once WC_ABSPATH . 'includes/interfaces/class-wc-customer-data-store-interface.php';
+ include_once WC_ABSPATH . 'includes/interfaces/class-wc-customer-download-data-store-interface.php';
+ include_once WC_ABSPATH . 'includes/interfaces/class-wc-customer-download-log-data-store-interface.php';
+ include_once WC_ABSPATH . 'includes/interfaces/class-wc-object-data-store-interface.php';
+ include_once WC_ABSPATH . 'includes/interfaces/class-wc-order-data-store-interface.php';
+ include_once WC_ABSPATH . 'includes/interfaces/class-wc-order-item-data-store-interface.php';
+ include_once WC_ABSPATH . 'includes/interfaces/class-wc-order-item-product-data-store-interface.php';
+ include_once WC_ABSPATH . 'includes/interfaces/class-wc-order-item-type-data-store-interface.php';
+ include_once WC_ABSPATH . 'includes/interfaces/class-wc-order-refund-data-store-interface.php';
+ include_once WC_ABSPATH . 'includes/interfaces/class-wc-payment-token-data-store-interface.php';
+ include_once WC_ABSPATH . 'includes/interfaces/class-wc-product-data-store-interface.php';
+ include_once WC_ABSPATH . 'includes/interfaces/class-wc-product-variable-data-store-interface.php';
+ include_once WC_ABSPATH . 'includes/interfaces/class-wc-shipping-zone-data-store-interface.php';
+ include_once WC_ABSPATH . 'includes/interfaces/class-wc-logger-interface.php';
+ include_once WC_ABSPATH . 'includes/interfaces/class-wc-log-handler-interface.php';
+ include_once WC_ABSPATH . 'includes/interfaces/class-wc-webhooks-data-store-interface.php';
+ include_once WC_ABSPATH . 'includes/interfaces/class-wc-queue-interface.php';
+
+ /**
+ * Core traits.
+ */
+ include_once WC_ABSPATH . 'includes/traits/trait-wc-item-totals.php';
+
+ /**
+ * Abstract classes.
+ */
+ include_once WC_ABSPATH . 'includes/abstracts/abstract-wc-data.php';
+ include_once WC_ABSPATH . 'includes/abstracts/abstract-wc-object-query.php';
+ include_once WC_ABSPATH . 'includes/abstracts/abstract-wc-payment-token.php';
+ include_once WC_ABSPATH . 'includes/abstracts/abstract-wc-product.php';
+ include_once WC_ABSPATH . 'includes/abstracts/abstract-wc-order.php';
+ include_once WC_ABSPATH . 'includes/abstracts/abstract-wc-settings-api.php';
+ include_once WC_ABSPATH . 'includes/abstracts/abstract-wc-shipping-method.php';
+ include_once WC_ABSPATH . 'includes/abstracts/abstract-wc-payment-gateway.php';
+ include_once WC_ABSPATH . 'includes/abstracts/abstract-wc-integration.php';
+ include_once WC_ABSPATH . 'includes/abstracts/abstract-wc-log-handler.php';
+ include_once WC_ABSPATH . 'includes/abstracts/abstract-wc-deprecated-hooks.php';
+ include_once WC_ABSPATH . 'includes/abstracts/abstract-wc-session.php';
+ include_once WC_ABSPATH . 'includes/abstracts/abstract-wc-privacy.php';
+
+ /**
+ * Core classes.
+ */
+ include_once WC_ABSPATH . 'includes/wc-core-functions.php';
+ include_once WC_ABSPATH . 'includes/class-wc-datetime.php';
+ include_once WC_ABSPATH . 'includes/class-wc-post-types.php';
+ include_once WC_ABSPATH . 'includes/class-wc-install.php';
+ include_once WC_ABSPATH . 'includes/class-wc-geolocation.php';
+ include_once WC_ABSPATH . 'includes/class-wc-download-handler.php';
+ include_once WC_ABSPATH . 'includes/class-wc-comments.php';
+ include_once WC_ABSPATH . 'includes/class-wc-post-data.php';
+ include_once WC_ABSPATH . 'includes/class-wc-ajax.php';
+ include_once WC_ABSPATH . 'includes/class-wc-emails.php';
+ include_once WC_ABSPATH . 'includes/class-wc-data-exception.php';
+ include_once WC_ABSPATH . 'includes/class-wc-query.php';
+ include_once WC_ABSPATH . 'includes/class-wc-meta-data.php';
+ include_once WC_ABSPATH . 'includes/class-wc-order-factory.php';
+ include_once WC_ABSPATH . 'includes/class-wc-order-query.php';
+ include_once WC_ABSPATH . 'includes/class-wc-product-factory.php';
+ include_once WC_ABSPATH . 'includes/class-wc-product-query.php';
+ include_once WC_ABSPATH . 'includes/class-wc-payment-tokens.php';
+ include_once WC_ABSPATH . 'includes/class-wc-shipping-zone.php';
+ include_once WC_ABSPATH . 'includes/gateways/class-wc-payment-gateway-cc.php';
+ include_once WC_ABSPATH . 'includes/gateways/class-wc-payment-gateway-echeck.php';
+ include_once WC_ABSPATH . 'includes/class-wc-countries.php';
+ include_once WC_ABSPATH . 'includes/class-wc-integrations.php';
+ include_once WC_ABSPATH . 'includes/class-wc-cache-helper.php';
+ include_once WC_ABSPATH . 'includes/class-wc-https.php';
+ include_once WC_ABSPATH . 'includes/class-wc-deprecated-action-hooks.php';
+ include_once WC_ABSPATH . 'includes/class-wc-deprecated-filter-hooks.php';
+ include_once WC_ABSPATH . 'includes/class-wc-background-emailer.php';
+ include_once WC_ABSPATH . 'includes/class-wc-discounts.php';
+ include_once WC_ABSPATH . 'includes/class-wc-cart-totals.php';
+ include_once WC_ABSPATH . 'includes/customizer/class-wc-shop-customizer.php';
+ include_once WC_ABSPATH . 'includes/class-wc-regenerate-images.php';
+ include_once WC_ABSPATH . 'includes/class-wc-privacy.php';
+ include_once WC_ABSPATH . 'includes/class-wc-structured-data.php';
+ include_once WC_ABSPATH . 'includes/class-wc-shortcodes.php';
+ include_once WC_ABSPATH . 'includes/class-wc-logger.php';
+ include_once WC_ABSPATH . 'includes/queue/class-wc-action-queue.php';
+ include_once WC_ABSPATH . 'includes/queue/class-wc-queue.php';
+ include_once WC_ABSPATH . 'includes/admin/marketplace-suggestions/class-wc-marketplace-updater.php';
+
+ /**
+ * Data stores - used to store and retrieve CRUD object data from the database.
+ */
+ include_once WC_ABSPATH . 'includes/class-wc-data-store.php';
+ include_once WC_ABSPATH . 'includes/data-stores/class-wc-data-store-wp.php';
+ include_once WC_ABSPATH . 'includes/data-stores/class-wc-coupon-data-store-cpt.php';
+ include_once WC_ABSPATH . 'includes/data-stores/class-wc-product-data-store-cpt.php';
+ include_once WC_ABSPATH . 'includes/data-stores/class-wc-product-grouped-data-store-cpt.php';
+ include_once WC_ABSPATH . 'includes/data-stores/class-wc-product-variable-data-store-cpt.php';
+ include_once WC_ABSPATH . 'includes/data-stores/class-wc-product-variation-data-store-cpt.php';
+ include_once WC_ABSPATH . 'includes/data-stores/abstract-wc-order-item-type-data-store.php';
+ include_once WC_ABSPATH . 'includes/data-stores/class-wc-order-item-data-store.php';
+ include_once WC_ABSPATH . 'includes/data-stores/class-wc-order-item-coupon-data-store.php';
+ include_once WC_ABSPATH . 'includes/data-stores/class-wc-order-item-fee-data-store.php';
+ include_once WC_ABSPATH . 'includes/data-stores/class-wc-order-item-product-data-store.php';
+ include_once WC_ABSPATH . 'includes/data-stores/class-wc-order-item-shipping-data-store.php';
+ include_once WC_ABSPATH . 'includes/data-stores/class-wc-order-item-tax-data-store.php';
+ include_once WC_ABSPATH . 'includes/data-stores/class-wc-payment-token-data-store.php';
+ include_once WC_ABSPATH . 'includes/data-stores/class-wc-customer-data-store.php';
+ include_once WC_ABSPATH . 'includes/data-stores/class-wc-customer-data-store-session.php';
+ include_once WC_ABSPATH . 'includes/data-stores/class-wc-customer-download-data-store.php';
+ include_once WC_ABSPATH . 'includes/data-stores/class-wc-customer-download-log-data-store.php';
+ include_once WC_ABSPATH . 'includes/data-stores/class-wc-shipping-zone-data-store.php';
+ include_once WC_ABSPATH . 'includes/data-stores/abstract-wc-order-data-store-cpt.php';
+ include_once WC_ABSPATH . 'includes/data-stores/class-wc-order-data-store-cpt.php';
+ include_once WC_ABSPATH . 'includes/data-stores/class-wc-order-refund-data-store-cpt.php';
+ include_once WC_ABSPATH . 'includes/data-stores/class-wc-webhook-data-store.php';
+
+ /**
+ * REST API.
+ */
+ include_once WC_ABSPATH . 'includes/legacy/class-wc-legacy-api.php';
+ include_once WC_ABSPATH . 'includes/class-wc-api.php';
+ include_once WC_ABSPATH . 'includes/class-wc-rest-authentication.php';
+ include_once WC_ABSPATH . 'includes/class-wc-rest-exception.php';
+ include_once WC_ABSPATH . 'includes/class-wc-auth.php';
+ include_once WC_ABSPATH . 'includes/class-wc-register-wp-admin-settings.php';
+
+ /**
+ * WCCOM Site.
+ */
+ include_once WC_ABSPATH . 'includes/wccom-site/class-wc-wccom-site.php';
+
+ /**
+ * Libraries and packages.
+ */
+ include_once WC_ABSPATH . 'packages/action-scheduler/action-scheduler.php';
+
+ if ( defined( 'WP_CLI' ) && WP_CLI ) {
+ include_once WC_ABSPATH . 'includes/class-wc-cli.php';
+ }
+
+ if ( $this->is_request( 'admin' ) ) {
+ include_once WC_ABSPATH . 'includes/admin/class-wc-admin.php';
+ }
+
+ if ( $this->is_request( 'frontend' ) ) {
+ $this->frontend_includes();
+ }
+
+ if ( $this->is_request( 'cron' ) && 'yes' === get_option( 'woocommerce_allow_tracking', 'no' ) ) {
+ include_once WC_ABSPATH . 'includes/class-wc-tracker.php';
+ }
+
+ $this->theme_support_includes();
+ $this->query = new WC_Query();
+ $this->api = new WC_API();
+ $this->api->init();
+ }
+
+ /**
+ * Include classes for theme support.
+ *
+ * @since 3.3.0
+ */
+ private function theme_support_includes() {
+ if ( wc_is_wp_default_theme_active() ) {
+ switch ( get_template() ) {
+ case 'twentyten':
+ include_once WC_ABSPATH . 'includes/theme-support/class-wc-twenty-ten.php';
+ break;
+ case 'twentyeleven':
+ include_once WC_ABSPATH . 'includes/theme-support/class-wc-twenty-eleven.php';
+ break;
+ case 'twentytwelve':
+ include_once WC_ABSPATH . 'includes/theme-support/class-wc-twenty-twelve.php';
+ break;
+ case 'twentythirteen':
+ include_once WC_ABSPATH . 'includes/theme-support/class-wc-twenty-thirteen.php';
+ break;
+ case 'twentyfourteen':
+ include_once WC_ABSPATH . 'includes/theme-support/class-wc-twenty-fourteen.php';
+ break;
+ case 'twentyfifteen':
+ include_once WC_ABSPATH . 'includes/theme-support/class-wc-twenty-fifteen.php';
+ break;
+ case 'twentysixteen':
+ include_once WC_ABSPATH . 'includes/theme-support/class-wc-twenty-sixteen.php';
+ break;
+ case 'twentyseventeen':
+ include_once WC_ABSPATH . 'includes/theme-support/class-wc-twenty-seventeen.php';
+ break;
+ case 'twentynineteen':
+ include_once WC_ABSPATH . 'includes/theme-support/class-wc-twenty-nineteen.php';
+ break;
+ case 'twentytwenty':
+ include_once WC_ABSPATH . 'includes/theme-support/class-wc-twenty-twenty.php';
+ break;
+ case 'twentytwentyone':
+ include_once WC_ABSPATH . 'includes/theme-support/class-wc-twenty-twenty-one.php';
+ break;
+ }
+ }
+ }
+
+ /**
+ * Include required frontend files.
+ */
+ public function frontend_includes() {
+ include_once WC_ABSPATH . 'includes/wc-cart-functions.php';
+ include_once WC_ABSPATH . 'includes/wc-notice-functions.php';
+ include_once WC_ABSPATH . 'includes/wc-template-hooks.php';
+ include_once WC_ABSPATH . 'includes/class-wc-template-loader.php';
+ include_once WC_ABSPATH . 'includes/class-wc-frontend-scripts.php';
+ include_once WC_ABSPATH . 'includes/class-wc-form-handler.php';
+ include_once WC_ABSPATH . 'includes/class-wc-cart.php';
+ include_once WC_ABSPATH . 'includes/class-wc-tax.php';
+ include_once WC_ABSPATH . 'includes/class-wc-shipping-zones.php';
+ include_once WC_ABSPATH . 'includes/class-wc-customer.php';
+ include_once WC_ABSPATH . 'includes/class-wc-embed.php';
+ include_once WC_ABSPATH . 'includes/class-wc-session-handler.php';
+ }
+
+ /**
+ * Function used to Init WooCommerce Template Functions - This makes them pluggable by plugins and themes.
+ */
+ public function include_template_functions() {
+ include_once WC_ABSPATH . 'includes/wc-template-functions.php';
+ }
+
+ /**
+ * Init WooCommerce when WordPress Initialises.
+ */
+ public function init() {
+ // Before init action.
+ do_action( 'before_woocommerce_init' );
+
+ // Set up localisation.
+ $this->load_plugin_textdomain();
+
+ // Load class instances.
+ $this->product_factory = new WC_Product_Factory();
+ $this->order_factory = new WC_Order_Factory();
+ $this->countries = new WC_Countries();
+ $this->integrations = new WC_Integrations();
+ $this->structured_data = new WC_Structured_Data();
+ $this->deprecated_hook_handlers['actions'] = new WC_Deprecated_Action_Hooks();
+ $this->deprecated_hook_handlers['filters'] = new WC_Deprecated_Filter_Hooks();
+
+ // Classes/actions loaded for the frontend and for ajax requests.
+ if ( $this->is_request( 'frontend' ) ) {
+ wc_load_cart();
+ }
+
+ $this->load_webhooks();
+
+ // Init action.
+ do_action( 'woocommerce_init' );
+ }
+
+ /**
+ * Load Localisation files.
+ *
+ * Note: the first-loaded translation file overrides any following ones if the same translation is present.
+ *
+ * Locales found in:
+ * - WP_LANG_DIR/woocommerce/woocommerce-LOCALE.mo
+ * - WP_LANG_DIR/plugins/woocommerce-LOCALE.mo
+ */
+ public function load_plugin_textdomain() {
+ if ( function_exists( 'determine_locale' ) ) {
+ $locale = determine_locale();
+ } else {
+ // @todo Remove when start supporting WP 5.0 or later.
+ $locale = is_admin() ? get_user_locale() : get_locale();
+ }
+
+ $locale = apply_filters( 'plugin_locale', $locale, 'woocommerce' );
+
+ unload_textdomain( 'woocommerce' );
+ load_textdomain( 'woocommerce', WP_LANG_DIR . '/woocommerce/woocommerce-' . $locale . '.mo' );
+ load_plugin_textdomain( 'woocommerce', false, plugin_basename( dirname( WC_PLUGIN_FILE ) ) . '/i18n/languages' );
+ }
+
+ /**
+ * Ensure theme and server variable compatibility and setup image sizes.
+ */
+ public function setup_environment() {
+ /**
+ * WC_TEMPLATE_PATH constant.
+ *
+ * @deprecated 2.2 Use WC()->template_path() instead.
+ */
+ $this->define( 'WC_TEMPLATE_PATH', $this->template_path() );
+
+ $this->add_thumbnail_support();
+ }
+
+ /**
+ * Ensure post thumbnail support is turned on.
+ */
+ private function add_thumbnail_support() {
+ if ( ! current_theme_supports( 'post-thumbnails' ) ) {
+ add_theme_support( 'post-thumbnails' );
+ }
+ add_post_type_support( 'product', 'thumbnail' );
+ }
+
+ /**
+ * Add WC Image sizes to WP.
+ *
+ * As of 3.3, image sizes can be registered via themes using add_theme_support for woocommerce
+ * and defining an array of args. If these are not defined, we will use defaults. This is
+ * handled in wc_get_image_size function.
+ *
+ * 3.3 sizes:
+ *
+ * woocommerce_thumbnail - Used in product listings. We assume these work for a 3 column grid layout.
+ * woocommerce_single - Used on single product pages for the main image.
+ *
+ * @since 2.3
+ */
+ public function add_image_sizes() {
+ $thumbnail = wc_get_image_size( 'thumbnail' );
+ $single = wc_get_image_size( 'single' );
+ $gallery_thumbnail = wc_get_image_size( 'gallery_thumbnail' );
+
+ add_image_size( 'woocommerce_thumbnail', $thumbnail['width'], $thumbnail['height'], $thumbnail['crop'] );
+ add_image_size( 'woocommerce_single', $single['width'], $single['height'], $single['crop'] );
+ add_image_size( 'woocommerce_gallery_thumbnail', $gallery_thumbnail['width'], $gallery_thumbnail['height'], $gallery_thumbnail['crop'] );
+
+ /**
+ * Legacy image sizes.
+ *
+ * @deprecated 3.3.0 These sizes will be removed in 4.6.0.
+ */
+ add_image_size( 'shop_catalog', $thumbnail['width'], $thumbnail['height'], $thumbnail['crop'] );
+ add_image_size( 'shop_single', $single['width'], $single['height'], $single['crop'] );
+ add_image_size( 'shop_thumbnail', $gallery_thumbnail['width'], $gallery_thumbnail['height'], $gallery_thumbnail['crop'] );
+ }
+
+ /**
+ * Get the plugin url.
+ *
+ * @return string
+ */
+ public function plugin_url() {
+ return untrailingslashit( plugins_url( '/', WC_PLUGIN_FILE ) );
+ }
+
+ /**
+ * Get the plugin path.
+ *
+ * @return string
+ */
+ public function plugin_path() {
+ return untrailingslashit( plugin_dir_path( WC_PLUGIN_FILE ) );
+ }
+
+ /**
+ * Get the template path.
+ *
+ * @return string
+ */
+ public function template_path() {
+ return apply_filters( 'woocommerce_template_path', 'woocommerce/' );
+ }
+
+ /**
+ * Get Ajax URL.
+ *
+ * @return string
+ */
+ public function ajax_url() {
+ return admin_url( 'admin-ajax.php', 'relative' );
+ }
+
+ /**
+ * Return the WC API URL for a given request.
+ *
+ * @param string $request Requested endpoint.
+ * @param bool|null $ssl If should use SSL, null if should auto detect. Default: null.
+ * @return string
+ */
+ public function api_request_url( $request, $ssl = null ) {
+ if ( is_null( $ssl ) ) {
+ $scheme = wp_parse_url( home_url(), PHP_URL_SCHEME );
+ } elseif ( $ssl ) {
+ $scheme = 'https';
+ } else {
+ $scheme = 'http';
+ }
+
+ if ( strstr( get_option( 'permalink_structure' ), '/index.php/' ) ) {
+ $api_request_url = trailingslashit( home_url( '/index.php/wc-api/' . $request, $scheme ) );
+ } elseif ( get_option( 'permalink_structure' ) ) {
+ $api_request_url = trailingslashit( home_url( '/wc-api/' . $request, $scheme ) );
+ } else {
+ $api_request_url = add_query_arg( 'wc-api', $request, trailingslashit( home_url( '', $scheme ) ) );
+ }
+
+ return esc_url_raw( apply_filters( 'woocommerce_api_request_url', $api_request_url, $request, $ssl ) );
+ }
+
+ /**
+ * Load & enqueue active webhooks.
+ *
+ * @since 2.2
+ */
+ private function load_webhooks() {
+
+ if ( ! is_blog_installed() ) {
+ return;
+ }
+
+ /**
+ * Hook: woocommerce_load_webhooks_limit.
+ *
+ * @since 3.6.0
+ * @param int $limit Used to limit how many webhooks are loaded. Default: no limit.
+ */
+ $limit = apply_filters( 'woocommerce_load_webhooks_limit', null );
+
+ wc_load_webhooks( 'active', $limit );
+ }
+
+ /**
+ * Initialize the customer and cart objects and setup customer saving on shutdown.
+ *
+ * @since 3.6.4
+ * @return void
+ */
+ public function initialize_cart() {
+ // Cart needs customer info.
+ if ( is_null( $this->customer ) || ! $this->customer instanceof WC_Customer ) {
+ $this->customer = new WC_Customer( get_current_user_id(), true );
+ // Customer should be saved during shutdown.
+ add_action( 'shutdown', array( $this->customer, 'save' ), 10 );
+ }
+ if ( is_null( $this->cart ) || ! $this->cart instanceof WC_Cart ) {
+ $this->cart = new WC_Cart();
+ }
+ }
+
+ /**
+ * Initialize the session class.
+ *
+ * @since 3.6.4
+ * @return void
+ */
+ public function initialize_session() {
+ // Session class, handles session data for users - can be overwritten if custom handler is needed.
+ $session_class = apply_filters( 'woocommerce_session_handler', 'WC_Session_Handler' );
+ if ( is_null( $this->session ) || ! $this->session instanceof $session_class ) {
+ $this->session = new $session_class();
+ $this->session->init();
+ }
+ }
+
+ /**
+ * Set tablenames inside WPDB object.
+ */
+ public function wpdb_table_fix() {
+ $this->define_tables();
+ }
+
+ /**
+ * Ran when any plugin is activated.
+ *
+ * @since 3.6.0
+ * @param string $filename The filename of the activated plugin.
+ */
+ public function activated_plugin( $filename ) {
+ include_once dirname( __FILE__ ) . '/admin/helper/class-wc-helper.php';
+
+ WC_Helper::activated_plugin( $filename );
+ }
+
+ /**
+ * Ran when any plugin is deactivated.
+ *
+ * @since 3.6.0
+ * @param string $filename The filename of the deactivated plugin.
+ */
+ public function deactivated_plugin( $filename ) {
+ include_once dirname( __FILE__ ) . '/admin/helper/class-wc-helper.php';
+
+ WC_Helper::deactivated_plugin( $filename );
+ }
+
+ /**
+ * Get queue instance.
+ *
+ * @return WC_Queue_Interface
+ */
+ public function queue() {
+ return WC_Queue::instance();
+ }
+
+ /**
+ * Get Checkout Class.
+ *
+ * @return WC_Checkout
+ */
+ public function checkout() {
+ return WC_Checkout::instance();
+ }
+
+ /**
+ * Get gateways class.
+ *
+ * @return WC_Payment_Gateways
+ */
+ public function payment_gateways() {
+ return WC_Payment_Gateways::instance();
+ }
+
+ /**
+ * Get shipping class.
+ *
+ * @return WC_Shipping
+ */
+ public function shipping() {
+ return WC_Shipping::instance();
+ }
+
+ /**
+ * Email Class.
+ *
+ * @return WC_Emails
+ */
+ public function mailer() {
+ return WC_Emails::instance();
+ }
+
+ /**
+ * Check if plugin assets are built and minified
+ *
+ * @return bool
+ */
+ public function build_dependencies_satisfied() {
+ // Check if we have compiled CSS.
+ if ( ! file_exists( WC()->plugin_path() . '/assets/css/admin.css' ) ) {
+ return false;
+ }
+
+ // Check if we have minified JS.
+ if ( ! file_exists( WC()->plugin_path() . '/assets/js/admin/woocommerce_admin.min.js' ) ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Output a admin notice when build dependencies not met.
+ *
+ * @return void
+ */
+ public function build_dependencies_notice() {
+ if ( $this->build_dependencies_satisfied() ) {
+ return;
+ }
+
+ $message_one = __( 'You have installed a development version of WooCommerce which requires files to be built and minified. From the plugin directory, run grunt assets
to build and minify assets.', 'woocommerce' );
+ $message_two = sprintf(
+ /* translators: 1: URL of WordPress.org Repository 2: URL of the GitHub Repository release page */
+ __( 'Or you can download a pre-built version of the plugin from the WordPress.org repository or by visiting the releases page in the GitHub repository.', 'woocommerce' ),
+ 'https://wordpress.org/plugins/woocommerce/',
+ 'https://github.com/woocommerce/woocommerce/releases'
+ );
+ printf( '
%s %s
', $message_one, $message_two ); /* WPCS: xss ok. */
+ }
+
+ /**
+ * Is the WooCommerce Admin actively included in the WooCommerce core?
+ * Based on presence of a basic WC Admin function.
+ *
+ * @return boolean
+ */
+ public function is_wc_admin_active() {
+ return function_exists( 'wc_admin_url' );
+ }
+
+ /**
+ * Call a user function. This should be used to execute any non-idempotent function, especially
+ * those in the `includes` directory or provided by WordPress.
+ *
+ * This method can be useful for unit tests, since functions called using this method
+ * can be easily mocked by using WC_Unit_Test_Case::register_legacy_proxy_function_mocks.
+ *
+ * @param string $function_name The function to execute.
+ * @param mixed ...$parameters The parameters to pass to the function.
+ *
+ * @return mixed The result from the function.
+ *
+ * @since 4.4
+ */
+ public function call_function( $function_name, ...$parameters ) {
+ return wc_get_container()->get( LegacyProxy::class )->call_function( $function_name, ...$parameters );
+ }
+
+ /**
+ * Call a static method in a class. This should be used to execute any non-idempotent method in classes
+ * from the `includes` directory.
+ *
+ * This method can be useful for unit tests, since methods called using this method
+ * can be easily mocked by using WC_Unit_Test_Case::register_legacy_proxy_static_mocks.
+ *
+ * @param string $class_name The name of the class containing the method.
+ * @param string $method_name The name of the method.
+ * @param mixed ...$parameters The parameters to pass to the method.
+ *
+ * @return mixed The result from the method.
+ *
+ * @since 4.4
+ */
+ public function call_static( $class_name, $method_name, ...$parameters ) {
+ return wc_get_container()->get( LegacyProxy::class )->call_static( $class_name, $method_name, ...$parameters );
+ }
+
+ /**
+ * Gets an instance of a given legacy class.
+ * This must not be used to get instances of classes in the `src` directory.
+ *
+ * This method can be useful for unit tests, since objects obtained using this method
+ * can be easily mocked by using WC_Unit_Test_Case::register_legacy_proxy_class_mocks.
+ *
+ * @param string $class_name The name of the class to get an instance for.
+ * @param mixed ...$args Parameters to be passed to the class constructor or to the appropriate internal 'get_instance_of_' method.
+ *
+ * @return object The instance of the class.
+ * @throws \Exception The requested class belongs to the `src` directory, or there was an error creating an instance of the class.
+ *
+ * @since 4.4
+ */
+ public function get_instance_of( string $class_name, ...$args ) {
+ return wc_get_container()->get( LegacyProxy::class )->get_instance_of( $class_name, ...$args );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/cli/class-wc-cli-rest-command.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/cli/class-wc-cli-rest-command.php
new file mode 100644
index 0000000..f4e2239
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/cli/class-wc-cli-rest-command.php
@@ -0,0 +1,467 @@
+ desc).
+ *
+ * @var array
+ */
+ private $supported_ids = array();
+
+ /**
+ * Sets up REST Command.
+ *
+ * @param string $name Name of endpoint object (comes from schema).
+ * @param string $route Path to route of this endpoint.
+ * @param array $schema Schema object.
+ */
+ public function __construct( $name, $route, $schema ) {
+ $this->name = $name;
+
+ preg_match_all( '#\([^\)]+\)#', $route, $matches );
+ $first_match = $matches[0];
+ $resource_id = ! empty( $matches[0] ) ? array_pop( $matches[0] ) : null;
+ $this->route = rtrim( $route );
+ $this->schema = $schema;
+
+ $this->resource_identifier = $resource_id;
+ if ( in_array( $name, $this->routes_with_parent_id, true ) ) {
+ $is_singular = substr( $this->route, - strlen( $resource_id ) ) === $resource_id;
+ if ( ! $is_singular ) {
+ $this->resource_identifier = $first_match[0];
+ }
+ }
+ }
+
+ /**
+ * Passes supported ID arguments (things like product_id, order_id, etc) that we should look for in addition to id.
+ *
+ * @param array $supported_ids List of supported IDs.
+ */
+ public function set_supported_ids( $supported_ids = array() ) {
+ $this->supported_ids = $supported_ids;
+ }
+
+ /**
+ * Returns an ID of supported ID arguments (things like product_id, order_id, etc) that we should look for in addition to id.
+ *
+ * @return array
+ */
+ public function get_supported_ids() {
+ return $this->supported_ids;
+ }
+
+ /**
+ * Create a new item.
+ *
+ * @subcommand create
+ *
+ * @param array $args WP-CLI positional arguments.
+ * @param array $assoc_args WP-CLI associative arguments.
+ */
+ public function create_item( $args, $assoc_args ) {
+ $assoc_args = self::decode_json( $assoc_args );
+ list( $status, $body ) = $this->do_request( 'POST', $this->get_filled_route( $args ), $assoc_args );
+ if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ) ) {
+ WP_CLI::line( $body['id'] );
+ } else {
+ WP_CLI::success( "Created {$this->name} {$body['id']}." );
+ }
+ }
+
+ /**
+ * Delete an existing item.
+ *
+ * @subcommand delete
+ *
+ * @param array $args WP-CLI positional arguments.
+ * @param array $assoc_args WP-CLI associative arguments.
+ */
+ public function delete_item( $args, $assoc_args ) {
+ list( $status, $body ) = $this->do_request( 'DELETE', $this->get_filled_route( $args ), $assoc_args );
+ $object_id = isset( $body['id'] ) ? $body['id'] : '';
+ if ( ! $object_id && isset( $body['slug'] ) ) {
+ $object_id = $body['slug'];
+ }
+
+ if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ) ) {
+ WP_CLI::line( $object_id );
+ } else {
+ if ( empty( $assoc_args['force'] ) ) {
+ WP_CLI::success( __( 'Trashed', 'woocommerce' ) . " {$this->name} {$object_id}" );
+ } else {
+ WP_CLI::success( __( 'Deleted', 'woocommerce' ) . " {$this->name} {$object_id}." );
+ }
+ }
+ }
+
+ /**
+ * Get a single item.
+ *
+ * @subcommand get
+ *
+ * @param array $args WP-CLI positional arguments.
+ * @param array $assoc_args WP-CLI associative arguments.
+ */
+ public function get_item( $args, $assoc_args ) {
+ $route = $this->get_filled_route( $args );
+ list( $status, $body, $headers ) = $this->do_request( 'GET', $route, $assoc_args );
+
+ if ( ! empty( $assoc_args['fields'] ) ) {
+ $body = self::limit_item_to_fields( $body, $assoc_args['fields'] );
+ }
+
+ if ( empty( $assoc_args['format'] ) ) {
+ $assoc_args['format'] = 'table';
+ }
+
+ if ( 'headers' === $assoc_args['format'] ) {
+ echo wp_json_encode( $headers );
+ } elseif ( 'body' === $assoc_args['format'] ) {
+ echo wp_json_encode( $body );
+ } elseif ( 'envelope' === $assoc_args['format'] ) {
+ echo wp_json_encode(
+ array(
+ 'body' => $body,
+ 'headers' => $headers,
+ 'status' => $status,
+ )
+ );
+ } else {
+ $formatter = $this->get_formatter( $assoc_args );
+ $formatter->display_item( $body );
+ }
+ }
+
+ /**
+ * List all items.
+ *
+ * @subcommand list
+ *
+ * @param array $args WP-CLI positional arguments.
+ * @param array $assoc_args WP-CLI associative arguments.
+ */
+ public function list_items( $args, $assoc_args ) {
+ if ( ! empty( $assoc_args['format'] ) && 'count' === $assoc_args['format'] ) {
+ $method = 'HEAD';
+ } else {
+ $method = 'GET';
+ }
+
+ if ( ! isset( $assoc_args['per_page'] ) || empty( $assoc_args['per_page'] ) ) {
+ $assoc_args['per_page'] = '100';
+ }
+
+ list( $status, $body, $headers ) = $this->do_request( $method, $this->get_filled_route( $args ), $assoc_args );
+ if ( ! empty( $assoc_args['format'] ) && 'ids' === $assoc_args['format'] ) {
+ $items = array_column( $body, 'id' );
+ } else {
+ $items = $body;
+ }
+
+ if ( ! empty( $assoc_args['fields'] ) ) {
+ foreach ( $items as $key => $item ) {
+ $items[ $key ] = self::limit_item_to_fields( $item, $assoc_args['fields'] );
+ }
+ }
+
+ if ( empty( $assoc_args['format'] ) ) {
+ $assoc_args['format'] = 'table';
+ }
+
+ if ( ! empty( $assoc_args['format'] ) && 'count' === $assoc_args['format'] ) {
+ echo (int) $headers['X-WP-Total'];
+ } elseif ( 'headers' === $assoc_args['format'] ) {
+ echo wp_json_encode( $headers );
+ } elseif ( 'body' === $assoc_args['format'] ) {
+ echo wp_json_encode( $body );
+ } elseif ( 'envelope' === $assoc_args['format'] ) {
+ echo wp_json_encode(
+ array(
+ 'body' => $body,
+ 'headers' => $headers,
+ 'status' => $status,
+ 'api_url' => $this->api_url,
+ )
+ );
+ } else {
+ $formatter = $this->get_formatter( $assoc_args );
+ $formatter->display_items( $items );
+ }
+ }
+
+ /**
+ * Update an existing item.
+ *
+ * @subcommand update
+ *
+ * @param array $args WP-CLI positional arguments.
+ * @param array $assoc_args WP-CLI associative arguments.
+ */
+ public function update_item( $args, $assoc_args ) {
+ $assoc_args = self::decode_json( $assoc_args );
+ list( $status, $body ) = $this->do_request( 'POST', $this->get_filled_route( $args ), $assoc_args );
+ if ( \WP_CLI\Utils\get_flag_value( $assoc_args, 'porcelain' ) ) {
+ WP_CLI::line( $body['id'] );
+ } else {
+ WP_CLI::success( __( 'Updated', 'woocommerce' ) . " {$this->name} {$body['id']}." );
+ }
+ }
+
+ /**
+ * Do a REST Request
+ *
+ * @param string $method Request method. Examples: 'POST', 'PUT', 'DELETE' or 'GET'.
+ * @param string $route Resource route.
+ * @param array $assoc_args Associative arguments passed to the originating WP-CLI command.
+ *
+ * @return array
+ */
+ private function do_request( $method, $route, $assoc_args ) {
+ wc_maybe_define_constant( 'REST_REQUEST', true );
+
+ $request = new WP_REST_Request( $method, $route );
+ if ( in_array( $method, array( 'POST', 'PUT' ), true ) ) {
+ $request->set_body_params( $assoc_args );
+ } else {
+ foreach ( $assoc_args as $key => $value ) {
+ $request->set_param( $key, $value );
+ }
+ }
+ if ( Constants::is_true( 'SAVEQUERIES' ) ) {
+ $original_queries = is_array( $GLOBALS['wpdb']->queries ) ? array_keys( $GLOBALS['wpdb']->queries ) : array();
+ }
+ $response = rest_do_request( $request );
+ if ( Constants::is_true( 'SAVEQUERIES' ) ) {
+ $performed_queries = array();
+ foreach ( (array) $GLOBALS['wpdb']->queries as $key => $query ) {
+ if ( in_array( $key, $original_queries, true ) ) {
+ continue;
+ }
+ $performed_queries[] = $query;
+ }
+ usort(
+ $performed_queries,
+ function( $a, $b ) {
+ if ( $a[1] === $b[1] ) {
+ return 0;
+ }
+ return ( $a[1] > $b[1] ) ? -1 : 1;
+ }
+ );
+
+ $query_count = count( $performed_queries );
+ $query_total_time = 0;
+ foreach ( $performed_queries as $query ) {
+ $query_total_time += $query[1];
+ }
+ $slow_query_message = '';
+ if ( $performed_queries && 'wc' === WP_CLI::get_config( 'debug' ) ) {
+ $slow_query_message .= '. Ordered by slowness, the queries are:' . PHP_EOL;
+ foreach ( $performed_queries as $i => $query ) {
+ $i++;
+ $bits = explode( ', ', $query[2] );
+ $backtrace = implode( ', ', array_slice( $bits, 13 ) );
+ $seconds = NumberUtil::round( $query[1], 6 );
+ $slow_query_message .= <<
+
+
+
+
+
+
+
+
+ ' . esc_html( trailingslashit( basename( get_stylesheet_directory() ) ) . $template_dir . '/' . $template ) . '' );
+ ?>
+
+
+
+
+
+
+
+
+
+ ' . esc_html( plugin_basename( $template_file ) ) . '', '
+
+ field_name( 'card-cvc' ) . ' style="width:100px" />
+
+
+ field_name( 'card-number' ) . ' />
+
+
+ field_name( 'card-expiry' ) . ' />
+
+
+
+
+
+
+
+ :
+
+ choices as $key => $radio ) : ?>
+
+ add_panel(
+ 'woocommerce',
+ array(
+ 'priority' => 200,
+ 'capability' => 'manage_woocommerce',
+ 'theme_supports' => '',
+ 'title' => __( 'WooCommerce', 'woocommerce' ),
+ )
+ );
+
+ $this->add_store_notice_section( $wp_customize );
+ $this->add_product_catalog_section( $wp_customize );
+ $this->add_product_images_section( $wp_customize );
+ $this->add_checkout_section( $wp_customize );
+ }
+
+ /**
+ * Frontend CSS styles.
+ */
+ public function add_frontend_scripts() {
+ if ( ! is_customize_preview() || ! is_store_notice_showing() ) {
+ return;
+ }
+
+ $css = '.woocommerce-store-notice, p.demo_store { display: block !important; }';
+ wp_add_inline_style( 'customize-preview', $css );
+ }
+
+ /**
+ * CSS styles to improve our form.
+ */
+ public function add_styles() {
+ ?>
+
+
+
+ __( 'Default sorting (custom ordering + name)', 'woocommerce' ),
+ 'popularity' => __( 'Popularity (sales)', 'woocommerce' ),
+ 'rating' => __( 'Average rating', 'woocommerce' ),
+ 'date' => __( 'Sort by most recent', 'woocommerce' ),
+ 'price' => __( 'Sort by price (asc)', 'woocommerce' ),
+ 'price-desc' => __( 'Sort by price (desc)', 'woocommerce' ),
+ )
+ );
+
+ return array_key_exists( $value, $options ) ? $value : 'menu_order';
+ }
+
+ /**
+ * Store notice section.
+ *
+ * @param WP_Customize_Manager $wp_customize Theme Customizer object.
+ */
+ private function add_store_notice_section( $wp_customize ) {
+ $wp_customize->add_section(
+ 'woocommerce_store_notice',
+ array(
+ 'title' => __( 'Store Notice', 'woocommerce' ),
+ 'priority' => 10,
+ 'panel' => 'woocommerce',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'woocommerce_demo_store',
+ array(
+ 'default' => 'no',
+ 'type' => 'option',
+ 'capability' => 'manage_woocommerce',
+ 'sanitize_callback' => 'wc_bool_to_string',
+ 'sanitize_js_callback' => 'wc_string_to_bool',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'woocommerce_demo_store_notice',
+ array(
+ 'default' => __( 'This is a demo store for testing purposes — no orders shall be fulfilled.', 'woocommerce' ),
+ 'type' => 'option',
+ 'capability' => 'manage_woocommerce',
+ 'sanitize_callback' => 'wp_kses_post',
+ 'transport' => 'postMessage',
+ )
+ );
+
+ $wp_customize->add_control(
+ 'woocommerce_demo_store_notice',
+ array(
+ 'label' => __( 'Store notice', 'woocommerce' ),
+ 'description' => __( 'If enabled, this text will be shown site-wide. You can use it to show events or promotions to visitors!', 'woocommerce' ),
+ 'section' => 'woocommerce_store_notice',
+ 'settings' => 'woocommerce_demo_store_notice',
+ 'type' => 'textarea',
+ )
+ );
+
+ $wp_customize->add_control(
+ 'woocommerce_demo_store',
+ array(
+ 'label' => __( 'Enable store notice', 'woocommerce' ),
+ 'section' => 'woocommerce_store_notice',
+ 'settings' => 'woocommerce_demo_store',
+ 'type' => 'checkbox',
+ )
+ );
+
+ if ( isset( $wp_customize->selective_refresh ) ) {
+ $wp_customize->selective_refresh->add_partial(
+ 'woocommerce_demo_store_notice',
+ array(
+ 'selector' => '.woocommerce-store-notice',
+ 'container_inclusive' => true,
+ 'render_callback' => 'woocommerce_demo_store',
+ )
+ );
+ }
+ }
+
+ /**
+ * Product catalog section.
+ *
+ * @param WP_Customize_Manager $wp_customize Theme Customizer object.
+ */
+ public function add_product_catalog_section( $wp_customize ) {
+ $wp_customize->add_section(
+ 'woocommerce_product_catalog',
+ array(
+ 'title' => __( 'Product Catalog', 'woocommerce' ),
+ 'priority' => 10,
+ 'panel' => 'woocommerce',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'woocommerce_shop_page_display',
+ array(
+ 'default' => '',
+ 'type' => 'option',
+ 'capability' => 'manage_woocommerce',
+ 'sanitize_callback' => array( $this, 'sanitize_archive_display' ),
+ )
+ );
+
+ $wp_customize->add_control(
+ 'woocommerce_shop_page_display',
+ array(
+ 'label' => __( 'Shop page display', 'woocommerce' ),
+ 'description' => __( 'Choose what to display on the main shop page.', 'woocommerce' ),
+ 'section' => 'woocommerce_product_catalog',
+ 'settings' => 'woocommerce_shop_page_display',
+ 'type' => 'select',
+ 'choices' => array(
+ '' => __( 'Show products', 'woocommerce' ),
+ 'subcategories' => __( 'Show categories', 'woocommerce' ),
+ 'both' => __( 'Show categories & products', 'woocommerce' ),
+ ),
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'woocommerce_category_archive_display',
+ array(
+ 'default' => '',
+ 'type' => 'option',
+ 'capability' => 'manage_woocommerce',
+ 'sanitize_callback' => array( $this, 'sanitize_archive_display' ),
+ )
+ );
+
+ $wp_customize->add_control(
+ 'woocommerce_category_archive_display',
+ array(
+ 'label' => __( 'Category display', 'woocommerce' ),
+ 'description' => __( 'Choose what to display on product category pages.', 'woocommerce' ),
+ 'section' => 'woocommerce_product_catalog',
+ 'settings' => 'woocommerce_category_archive_display',
+ 'type' => 'select',
+ 'choices' => array(
+ '' => __( 'Show products', 'woocommerce' ),
+ 'subcategories' => __( 'Show subcategories', 'woocommerce' ),
+ 'both' => __( 'Show subcategories & products', 'woocommerce' ),
+ ),
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'woocommerce_default_catalog_orderby',
+ array(
+ 'default' => 'menu_order',
+ 'type' => 'option',
+ 'capability' => 'manage_woocommerce',
+ 'sanitize_callback' => array( $this, 'sanitize_default_catalog_orderby' ),
+ )
+ );
+
+ $wp_customize->add_control(
+ 'woocommerce_default_catalog_orderby',
+ array(
+ 'label' => __( 'Default product sorting', 'woocommerce' ),
+ 'description' => __( 'How should products be sorted in the catalog by default?', 'woocommerce' ),
+ 'section' => 'woocommerce_product_catalog',
+ 'settings' => 'woocommerce_default_catalog_orderby',
+ 'type' => 'select',
+ 'choices' => apply_filters(
+ 'woocommerce_default_catalog_orderby_options',
+ array(
+ 'menu_order' => __( 'Default sorting (custom ordering + name)', 'woocommerce' ),
+ 'popularity' => __( 'Popularity (sales)', 'woocommerce' ),
+ 'rating' => __( 'Average rating', 'woocommerce' ),
+ 'date' => __( 'Sort by most recent', 'woocommerce' ),
+ 'price' => __( 'Sort by price (asc)', 'woocommerce' ),
+ 'price-desc' => __( 'Sort by price (desc)', 'woocommerce' ),
+ )
+ ),
+ )
+ );
+
+ // The following settings should be hidden if the theme is declaring the values.
+ if ( has_filter( 'loop_shop_columns' ) ) {
+ return;
+ }
+
+ $wp_customize->add_setting(
+ 'woocommerce_catalog_columns',
+ array(
+ 'default' => 4,
+ 'type' => 'option',
+ 'capability' => 'manage_woocommerce',
+ 'sanitize_callback' => 'absint',
+ 'sanitize_js_callback' => 'absint',
+ )
+ );
+
+ $wp_customize->add_control(
+ 'woocommerce_catalog_columns',
+ array(
+ 'label' => __( 'Products per row', 'woocommerce' ),
+ 'description' => __( 'How many products should be shown per row?', 'woocommerce' ),
+ 'section' => 'woocommerce_product_catalog',
+ 'settings' => 'woocommerce_catalog_columns',
+ 'type' => 'number',
+ 'input_attrs' => array(
+ 'min' => wc_get_theme_support( 'product_grid::min_columns', 1 ),
+ 'max' => wc_get_theme_support( 'product_grid::max_columns', '' ),
+ 'step' => 1,
+ ),
+ )
+ );
+
+ // Only add this setting if something else isn't managing the number of products per page.
+ if ( ! has_filter( 'loop_shop_per_page' ) ) {
+ $wp_customize->add_setting(
+ 'woocommerce_catalog_rows',
+ array(
+ 'default' => 4,
+ 'type' => 'option',
+ 'capability' => 'manage_woocommerce',
+ 'sanitize_callback' => 'absint',
+ 'sanitize_js_callback' => 'absint',
+ )
+ );
+ }
+
+ $wp_customize->add_control(
+ 'woocommerce_catalog_rows',
+ array(
+ 'label' => __( 'Rows per page', 'woocommerce' ),
+ 'description' => __( 'How many rows of products should be shown per page?', 'woocommerce' ),
+ 'section' => 'woocommerce_product_catalog',
+ 'settings' => 'woocommerce_catalog_rows',
+ 'type' => 'number',
+ 'input_attrs' => array(
+ 'min' => wc_get_theme_support( 'product_grid::min_rows', 1 ),
+ 'max' => wc_get_theme_support( 'product_grid::max_rows', '' ),
+ 'step' => 1,
+ ),
+ )
+ );
+ }
+
+ /**
+ * Product images section.
+ *
+ * @param WP_Customize_Manager $wp_customize Theme Customizer object.
+ */
+ private function add_product_images_section( $wp_customize ) {
+ if ( class_exists( 'Jetpack' ) && Jetpack::is_module_active( 'photon' ) ) {
+ $regen_description = ''; // Nothing to report; Jetpack will handle magically.
+ } elseif ( apply_filters( 'woocommerce_background_image_regeneration', true ) && ! is_multisite() ) {
+ $regen_description = __( 'After publishing your changes, new image sizes will be generated automatically.', 'woocommerce' );
+ } elseif ( apply_filters( 'woocommerce_background_image_regeneration', true ) && is_multisite() ) {
+ /* translators: 1: tools URL 2: regen thumbs url */
+ $regen_description = sprintf( __( 'After publishing your changes, new image sizes may not be shown until you regenerate thumbnails. You can do this from the tools section in WooCommerce or by using a plugin such as Regenerate Thumbnails.', 'woocommerce' ), admin_url( 'admin.php?page=wc-status&tab=tools' ), 'https://en-gb.wordpress.org/plugins/regenerate-thumbnails/' );
+ } else {
+ /* translators: %s: regen thumbs url */
+ $regen_description = sprintf( __( 'After publishing your changes, new image sizes may not be shown until you Regenerate Thumbnails.', 'woocommerce' ), 'https://en-gb.wordpress.org/plugins/regenerate-thumbnails/' );
+ }
+
+ $wp_customize->add_section(
+ 'woocommerce_product_images',
+ array(
+ 'title' => __( 'Product Images', 'woocommerce' ),
+ 'description' => $regen_description,
+ 'priority' => 20,
+ 'panel' => 'woocommerce',
+ )
+ );
+
+ if ( ! wc_get_theme_support( 'single_image_width' ) ) {
+ $wp_customize->add_setting(
+ 'woocommerce_single_image_width',
+ array(
+ 'default' => 600,
+ 'type' => 'option',
+ 'capability' => 'manage_woocommerce',
+ 'sanitize_callback' => 'absint',
+ 'sanitize_js_callback' => 'absint',
+ )
+ );
+
+ $wp_customize->add_control(
+ 'woocommerce_single_image_width',
+ array(
+ 'label' => __( 'Main image width', 'woocommerce' ),
+ 'description' => __( 'Image size used for the main image on single product pages. These images will remain uncropped.', 'woocommerce' ),
+ 'section' => 'woocommerce_product_images',
+ 'settings' => 'woocommerce_single_image_width',
+ 'type' => 'number',
+ 'input_attrs' => array(
+ 'min' => 0,
+ 'step' => 1,
+ ),
+ )
+ );
+ }
+
+ if ( ! wc_get_theme_support( 'thumbnail_image_width' ) ) {
+ $wp_customize->add_setting(
+ 'woocommerce_thumbnail_image_width',
+ array(
+ 'default' => 300,
+ 'type' => 'option',
+ 'capability' => 'manage_woocommerce',
+ 'sanitize_callback' => 'absint',
+ 'sanitize_js_callback' => 'absint',
+ )
+ );
+
+ $wp_customize->add_control(
+ 'woocommerce_thumbnail_image_width',
+ array(
+ 'label' => __( 'Thumbnail width', 'woocommerce' ),
+ 'description' => __( 'Image size used for products in the catalog.', 'woocommerce' ),
+ 'section' => 'woocommerce_product_images',
+ 'settings' => 'woocommerce_thumbnail_image_width',
+ 'type' => 'number',
+ 'input_attrs' => array(
+ 'min' => 0,
+ 'step' => 1,
+ ),
+ )
+ );
+ }
+
+ include_once WC_ABSPATH . 'includes/customizer/class-wc-customizer-control-cropping.php';
+
+ $wp_customize->add_setting(
+ 'woocommerce_thumbnail_cropping',
+ array(
+ 'default' => '1:1',
+ 'type' => 'option',
+ 'capability' => 'manage_woocommerce',
+ 'sanitize_callback' => 'wc_clean',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'woocommerce_thumbnail_cropping_custom_width',
+ array(
+ 'default' => '4',
+ 'type' => 'option',
+ 'capability' => 'manage_woocommerce',
+ 'sanitize_callback' => 'absint',
+ 'sanitize_js_callback' => 'absint',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'woocommerce_thumbnail_cropping_custom_height',
+ array(
+ 'default' => '3',
+ 'type' => 'option',
+ 'capability' => 'manage_woocommerce',
+ 'sanitize_callback' => 'absint',
+ 'sanitize_js_callback' => 'absint',
+ )
+ );
+
+ $wp_customize->add_control(
+ new WC_Customizer_Control_Cropping(
+ $wp_customize,
+ 'woocommerce_thumbnail_cropping',
+ array(
+ 'section' => 'woocommerce_product_images',
+ 'settings' => array(
+ 'cropping' => 'woocommerce_thumbnail_cropping',
+ 'custom_width' => 'woocommerce_thumbnail_cropping_custom_width',
+ 'custom_height' => 'woocommerce_thumbnail_cropping_custom_height',
+ ),
+ 'label' => __( 'Thumbnail cropping', 'woocommerce' ),
+ 'choices' => array(
+ '1:1' => array(
+ 'label' => __( '1:1', 'woocommerce' ),
+ 'description' => __( 'Images will be cropped into a square', 'woocommerce' ),
+ ),
+ 'custom' => array(
+ 'label' => __( 'Custom', 'woocommerce' ),
+ 'description' => __( 'Images will be cropped to a custom aspect ratio', 'woocommerce' ),
+ ),
+ 'uncropped' => array(
+ 'label' => __( 'Uncropped', 'woocommerce' ),
+ 'description' => __( 'Images will display using the aspect ratio in which they were uploaded', 'woocommerce' ),
+ ),
+ ),
+ )
+ )
+ );
+ }
+
+ /**
+ * Checkout section.
+ *
+ * @param WP_Customize_Manager $wp_customize Theme Customizer object.
+ */
+ public function add_checkout_section( $wp_customize ) {
+ $wp_customize->add_section(
+ 'woocommerce_checkout',
+ array(
+ 'title' => __( 'Checkout', 'woocommerce' ),
+ 'priority' => 20,
+ 'panel' => 'woocommerce',
+ 'description' => __( 'These options let you change the appearance of the WooCommerce checkout.', 'woocommerce' ),
+ )
+ );
+
+ // Checkout field controls.
+ $fields = array(
+ 'company' => __( 'Company name', 'woocommerce' ),
+ 'address_2' => __( 'Address line 2', 'woocommerce' ),
+ 'phone' => __( 'Phone', 'woocommerce' ),
+ );
+ foreach ( $fields as $field => $label ) {
+ $wp_customize->add_setting(
+ 'woocommerce_checkout_' . $field . '_field',
+ array(
+ 'default' => 'phone' === $field ? 'required' : 'optional',
+ 'type' => 'option',
+ 'capability' => 'manage_woocommerce',
+ 'sanitize_callback' => array( $this, 'sanitize_checkout_field_display' ),
+ )
+ );
+ $wp_customize->add_control(
+ 'woocommerce_checkout_' . $field . '_field',
+ array(
+ /* Translators: %s field name. */
+ 'label' => sprintf( __( '%s field', 'woocommerce' ), $label ),
+ 'section' => 'woocommerce_checkout',
+ 'settings' => 'woocommerce_checkout_' . $field . '_field',
+ 'type' => 'select',
+ 'choices' => array(
+ 'hidden' => __( 'Hidden', 'woocommerce' ),
+ 'optional' => __( 'Optional', 'woocommerce' ),
+ 'required' => __( 'Required', 'woocommerce' ),
+ ),
+ )
+ );
+ }
+
+ // Register settings.
+ $wp_customize->add_setting(
+ 'woocommerce_checkout_highlight_required_fields',
+ array(
+ 'default' => 'yes',
+ 'type' => 'option',
+ 'capability' => 'manage_woocommerce',
+ 'sanitize_callback' => 'wc_bool_to_string',
+ 'sanitize_js_callback' => 'wc_string_to_bool',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'woocommerce_checkout_terms_and_conditions_checkbox_text',
+ array(
+ /* translators: %s terms and conditions page name and link */
+ 'default' => sprintf( __( 'I have read and agree to the website %s', 'woocommerce' ), '[terms]' ),
+ 'type' => 'option',
+ 'capability' => 'manage_woocommerce',
+ 'sanitize_callback' => 'wp_kses_post',
+ 'transport' => 'postMessage',
+ )
+ );
+
+ $wp_customize->add_setting(
+ 'woocommerce_checkout_privacy_policy_text',
+ array(
+ /* translators: %s privacy policy page name and link */
+ 'default' => sprintf( __( 'Your personal data will be used to process your order, support your experience throughout this website, and for other purposes described in our %s.', 'woocommerce' ), '[privacy_policy]' ),
+ 'type' => 'option',
+ 'capability' => 'manage_woocommerce',
+ 'sanitize_callback' => 'wp_kses_post',
+ 'transport' => 'postMessage',
+ )
+ );
+
+ // Register controls.
+ $wp_customize->add_control(
+ 'woocommerce_checkout_highlight_required_fields',
+ array(
+ 'label' => __( 'Highlight required fields with an asterisk', 'woocommerce' ),
+ 'section' => 'woocommerce_checkout',
+ 'settings' => 'woocommerce_checkout_highlight_required_fields',
+ 'type' => 'checkbox',
+ )
+ );
+
+ if ( current_user_can( 'manage_privacy_options' ) ) {
+ $choose_pages = array(
+ 'wp_page_for_privacy_policy' => __( 'Privacy policy', 'woocommerce' ),
+ 'woocommerce_terms_page_id' => __( 'Terms and conditions', 'woocommerce' ),
+ );
+ } else {
+ $choose_pages = array(
+ 'woocommerce_terms_page_id' => __( 'Terms and conditions', 'woocommerce' ),
+ );
+ }
+ $pages = get_pages(
+ array(
+ 'post_type' => 'page',
+ 'post_status' => 'publish,private,draft',
+ 'child_of' => 0,
+ 'parent' => -1,
+ 'exclude' => array(
+ wc_get_page_id( 'cart' ),
+ wc_get_page_id( 'checkout' ),
+ wc_get_page_id( 'myaccount' ),
+ ),
+ 'sort_order' => 'asc',
+ 'sort_column' => 'post_title',
+ )
+ );
+ $page_choices = array( '' => __( 'No page set', 'woocommerce' ) ) + array_combine( array_map( 'strval', wp_list_pluck( $pages, 'ID' ) ), wp_list_pluck( $pages, 'post_title' ) );
+
+ foreach ( $choose_pages as $id => $name ) {
+ $wp_customize->add_setting(
+ $id,
+ array(
+ 'default' => '',
+ 'type' => 'option',
+ 'capability' => 'manage_woocommerce',
+ )
+ );
+ $wp_customize->add_control(
+ $id,
+ array(
+ /* Translators: %s: page name. */
+ 'label' => sprintf( __( '%s page', 'woocommerce' ), $name ),
+ 'section' => 'woocommerce_checkout',
+ 'settings' => $id,
+ 'type' => 'select',
+ 'choices' => $page_choices,
+ )
+ );
+ }
+
+ $wp_customize->add_control(
+ 'woocommerce_checkout_privacy_policy_text',
+ array(
+ 'label' => __( 'Privacy policy', 'woocommerce' ),
+ 'description' => __( 'Optionally add some text about your store privacy policy to show during checkout.', 'woocommerce' ),
+ 'section' => 'woocommerce_checkout',
+ 'settings' => 'woocommerce_checkout_privacy_policy_text',
+ 'active_callback' => 'wc_privacy_policy_page_id',
+ 'type' => 'textarea',
+ )
+ );
+
+ $wp_customize->add_control(
+ 'woocommerce_checkout_terms_and_conditions_checkbox_text',
+ array(
+ 'label' => __( 'Terms and conditions', 'woocommerce' ),
+ 'description' => __( 'Optionally add some text for the terms checkbox that customers must accept.', 'woocommerce' ),
+ 'section' => 'woocommerce_checkout',
+ 'settings' => 'woocommerce_checkout_terms_and_conditions_checkbox_text',
+ 'active_callback' => 'wc_terms_and_conditions_page_id',
+ 'type' => 'text',
+ )
+ );
+
+ if ( isset( $wp_customize->selective_refresh ) ) {
+ $wp_customize->selective_refresh->add_partial(
+ 'woocommerce_checkout_privacy_policy_text',
+ array(
+ 'selector' => '.woocommerce-privacy-policy-text',
+ 'container_inclusive' => true,
+ 'render_callback' => 'wc_checkout_privacy_policy_text',
+ )
+ );
+ $wp_customize->selective_refresh->add_partial(
+ 'woocommerce_checkout_terms_and_conditions_checkbox_text',
+ array(
+ 'selector' => '.woocommerce-terms-and-conditions-checkbox-text',
+ 'container_inclusive' => false,
+ 'render_callback' => 'wc_terms_and_conditions_checkbox_text',
+ )
+ );
+ }
+ }
+
+ /**
+ * Sanitize field display.
+ *
+ * @param string $value '', 'subcategories', or 'both'.
+ * @return string
+ */
+ public function sanitize_checkout_field_display( $value ) {
+ $options = array( 'hidden', 'optional', 'required' );
+ return in_array( $value, $options, true ) ? $value : '';
+ }
+}
+
+new WC_Shop_Customizer();
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/abstract-wc-order-data-store-cpt.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/abstract-wc-order-data-store-cpt.php
new file mode 100644
index 0000000..4081bbe
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/abstract-wc-order-data-store-cpt.php
@@ -0,0 +1,439 @@
+set_version( Constants::get_constant( 'WC_VERSION' ) );
+ $order->set_currency( $order->get_currency() ? $order->get_currency() : get_woocommerce_currency() );
+ if ( ! $order->get_date_created( 'edit' ) ) {
+ $order->set_date_created( time() );
+ }
+
+ $id = wp_insert_post(
+ apply_filters(
+ 'woocommerce_new_order_data',
+ array(
+ 'post_date' => gmdate( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getOffsetTimestamp() ),
+ 'post_date_gmt' => gmdate( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ),
+ 'post_type' => $order->get_type( 'edit' ),
+ 'post_status' => $this->get_post_status( $order ),
+ 'ping_status' => 'closed',
+ 'post_author' => 1,
+ 'post_title' => $this->get_post_title(),
+ 'post_password' => $this->get_order_key( $order ),
+ 'post_parent' => $order->get_parent_id( 'edit' ),
+ 'post_excerpt' => $this->get_post_excerpt( $order ),
+ )
+ ),
+ true
+ );
+
+ if ( $id && ! is_wp_error( $id ) ) {
+ $order->set_id( $id );
+ $this->update_post_meta( $order );
+ $order->save_meta_data();
+ $order->apply_changes();
+ $this->clear_caches( $order );
+ }
+ }
+
+ /**
+ * Method to read an order from the database.
+ *
+ * @param WC_Data $order Order object.
+ *
+ * @throws Exception If passed order is invalid.
+ */
+ public function read( &$order ) {
+ $order->set_defaults();
+ $post_object = get_post( $order->get_id() );
+
+ if ( ! $order->get_id() || ! $post_object || ! in_array( $post_object->post_type, wc_get_order_types(), true ) ) {
+ throw new Exception( __( 'Invalid order.', 'woocommerce' ) );
+ }
+
+ $order->set_props(
+ array(
+ 'parent_id' => $post_object->post_parent,
+ 'date_created' => $this->string_to_timestamp( $post_object->post_date_gmt ),
+ 'date_modified' => $this->string_to_timestamp( $post_object->post_modified_gmt ),
+ 'status' => $post_object->post_status,
+ )
+ );
+
+ $this->read_order_data( $order, $post_object );
+ $order->read_meta_data();
+ $order->set_object_read( true );
+
+ /**
+ * In older versions, discounts may have been stored differently.
+ * Update them now so if the object is saved, the correct values are
+ * stored. @todo When meta is flattened, handle this during migration.
+ */
+ if ( version_compare( $order->get_version( 'edit' ), '2.3.7', '<' ) && $order->get_prices_include_tax( 'edit' ) ) {
+ $order->set_discount_total( (float) get_post_meta( $order->get_id(), '_cart_discount', true ) - (float) get_post_meta( $order->get_id(), '_cart_discount_tax', true ) );
+ }
+ }
+
+ /**
+ * Method to update an order in the database.
+ *
+ * @param WC_Order $order Order object.
+ */
+ public function update( &$order ) {
+ $order->save_meta_data();
+ $order->set_version( Constants::get_constant( 'WC_VERSION' ) );
+
+ if ( null === $order->get_date_created( 'edit' ) ) {
+ $order->set_date_created( time() );
+ }
+
+ $changes = $order->get_changes();
+
+ // Only update the post when the post data changes.
+ if ( array_intersect( array( 'date_created', 'date_modified', 'status', 'parent_id', 'post_excerpt' ), array_keys( $changes ) ) ) {
+ $post_data = array(
+ 'post_date' => gmdate( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getOffsetTimestamp() ),
+ 'post_date_gmt' => gmdate( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ),
+ 'post_status' => $this->get_post_status( $order ),
+ 'post_parent' => $order->get_parent_id(),
+ 'post_excerpt' => $this->get_post_excerpt( $order ),
+ 'post_modified' => isset( $changes['date_modified'] ) ? gmdate( 'Y-m-d H:i:s', $order->get_date_modified( 'edit' )->getOffsetTimestamp() ) : current_time( 'mysql' ),
+ 'post_modified_gmt' => isset( $changes['date_modified'] ) ? gmdate( 'Y-m-d H:i:s', $order->get_date_modified( 'edit' )->getTimestamp() ) : current_time( 'mysql', 1 ),
+ );
+
+ /**
+ * When updating this object, to prevent infinite loops, use $wpdb
+ * to update data, since wp_update_post spawns more calls to the
+ * save_post action.
+ *
+ * This ensures hooks are fired by either WP itself (admin screen save),
+ * or an update purely from CRUD.
+ */
+ if ( doing_action( 'save_post' ) ) {
+ $GLOBALS['wpdb']->update( $GLOBALS['wpdb']->posts, $post_data, array( 'ID' => $order->get_id() ) );
+ clean_post_cache( $order->get_id() );
+ } else {
+ wp_update_post( array_merge( array( 'ID' => $order->get_id() ), $post_data ) );
+ }
+ $order->read_meta_data( true ); // Refresh internal meta data, in case things were hooked into `save_post` or another WP hook.
+ }
+ $this->update_post_meta( $order );
+ $order->apply_changes();
+ $this->clear_caches( $order );
+ }
+
+ /**
+ * Method to delete an order from the database.
+ *
+ * @param WC_Order $order Order object.
+ * @param array $args Array of args to pass to the delete method.
+ *
+ * @return void
+ */
+ public function delete( &$order, $args = array() ) {
+ $id = $order->get_id();
+ $args = wp_parse_args(
+ $args,
+ array(
+ 'force_delete' => false,
+ )
+ );
+
+ if ( ! $id ) {
+ return;
+ }
+
+ if ( $args['force_delete'] ) {
+ wp_delete_post( $id );
+ $order->set_id( 0 );
+ do_action( 'woocommerce_delete_order', $id );
+ } else {
+ wp_trash_post( $id );
+ $order->set_status( 'trash' );
+ do_action( 'woocommerce_trash_order', $id );
+ }
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Additional Methods
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Get the status to save to the post object.
+ *
+ * Plugins extending the order classes can override this to change the stored status/add prefixes etc.
+ *
+ * @since 3.6.0
+ * @param WC_order $order Order object.
+ * @return string
+ */
+ protected function get_post_status( $order ) {
+ $order_status = $order->get_status( 'edit' );
+
+ if ( ! $order_status ) {
+ $order_status = apply_filters( 'woocommerce_default_order_status', 'pending' );
+ }
+
+ $post_status = $order_status;
+ $valid_statuses = get_post_stati();
+
+ // Add a wc- prefix to the status, but exclude some core statuses which should not be prefixed.
+ // @todo In the future this should only happen based on `wc_is_order_status`, but in order to
+ // preserve back-compatibility this happens to all statuses except a select few. A doing_it_wrong
+ // Notice will be needed here, followed by future removal.
+ if ( ! in_array( $post_status, array( 'auto-draft', 'draft', 'trash' ), true ) && in_array( 'wc-' . $post_status, $valid_statuses, true ) ) {
+ $post_status = 'wc-' . $post_status;
+ }
+
+ return $post_status;
+ }
+
+ /**
+ * Excerpt for post.
+ *
+ * @param WC_order $order Order object.
+ * @return string
+ */
+ protected function get_post_excerpt( $order ) {
+ return '';
+ }
+
+ /**
+ * Get a title for the new post type.
+ *
+ * @return string
+ */
+ protected function get_post_title() {
+ // @codingStandardsIgnoreStart
+ /* translators: %s: Order date */
+ return sprintf( __( 'Order – %s', 'woocommerce' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Order date parsed by strftime', 'woocommerce' ) ) );
+ // @codingStandardsIgnoreEnd
+ }
+
+ /**
+ * Get order key.
+ *
+ * @since 4.3.0
+ * @param WC_order $order Order object.
+ * @return string
+ */
+ protected function get_order_key( $order ) {
+ return wc_generate_order_key();
+ }
+
+ /**
+ * Read order data. Can be overridden by child classes to load other props.
+ *
+ * @param WC_Order $order Order object.
+ * @param object $post_object Post object.
+ * @since 3.0.0
+ */
+ protected function read_order_data( &$order, $post_object ) {
+ $id = $order->get_id();
+
+ $order->set_props(
+ array(
+ 'currency' => get_post_meta( $id, '_order_currency', true ),
+ 'discount_total' => get_post_meta( $id, '_cart_discount', true ),
+ 'discount_tax' => get_post_meta( $id, '_cart_discount_tax', true ),
+ 'shipping_total' => get_post_meta( $id, '_order_shipping', true ),
+ 'shipping_tax' => get_post_meta( $id, '_order_shipping_tax', true ),
+ 'cart_tax' => get_post_meta( $id, '_order_tax', true ),
+ 'total' => get_post_meta( $id, '_order_total', true ),
+ 'version' => get_post_meta( $id, '_order_version', true ),
+ 'prices_include_tax' => metadata_exists( 'post', $id, '_prices_include_tax' ) ? 'yes' === get_post_meta( $id, '_prices_include_tax', true ) : 'yes' === get_option( 'woocommerce_prices_include_tax' ),
+ )
+ );
+
+ // Gets extra data associated with the order if needed.
+ foreach ( $order->get_extra_data_keys() as $key ) {
+ $function = 'set_' . $key;
+ if ( is_callable( array( $order, $function ) ) ) {
+ $order->{$function}( get_post_meta( $order->get_id(), '_' . $key, true ) );
+ }
+ }
+ }
+
+ /**
+ * Helper method that updates all the post meta for an order based on it's settings in the WC_Order class.
+ *
+ * @param WC_Order $order Order object.
+ * @since 3.0.0
+ */
+ protected function update_post_meta( &$order ) {
+ $updated_props = array();
+ $meta_key_to_props = array(
+ '_order_currency' => 'currency',
+ '_cart_discount' => 'discount_total',
+ '_cart_discount_tax' => 'discount_tax',
+ '_order_shipping' => 'shipping_total',
+ '_order_shipping_tax' => 'shipping_tax',
+ '_order_tax' => 'cart_tax',
+ '_order_total' => 'total',
+ '_order_version' => 'version',
+ '_prices_include_tax' => 'prices_include_tax',
+ );
+
+ $props_to_update = $this->get_props_to_update( $order, $meta_key_to_props );
+
+ foreach ( $props_to_update as $meta_key => $prop ) {
+ $value = $order->{"get_$prop"}( 'edit' );
+ $value = is_string( $value ) ? wp_slash( $value ) : $value;
+
+ if ( 'prices_include_tax' === $prop ) {
+ $value = $value ? 'yes' : 'no';
+ }
+
+ $updated = $this->update_or_delete_post_meta( $order, $meta_key, $value );
+
+ if ( $updated ) {
+ $updated_props[] = $prop;
+ }
+ }
+
+ do_action( 'woocommerce_order_object_updated_props', $order, $updated_props );
+ }
+
+ /**
+ * Clear any caches.
+ *
+ * @param WC_Order $order Order object.
+ * @since 3.0.0
+ */
+ protected function clear_caches( &$order ) {
+ clean_post_cache( $order->get_id() );
+ wc_delete_shop_order_transients( $order );
+ wp_cache_delete( 'order-items-' . $order->get_id(), 'orders' );
+ }
+
+ /**
+ * Read order items of a specific type from the database for this order.
+ *
+ * @param WC_Order $order Order object.
+ * @param string $type Order item type.
+ * @return array
+ */
+ public function read_items( $order, $type ) {
+ global $wpdb;
+
+ // Get from cache if available.
+ $items = 0 < $order->get_id() ? wp_cache_get( 'order-items-' . $order->get_id(), 'orders' ) : false;
+
+ if ( false === $items ) {
+ $items = $wpdb->get_results(
+ $wpdb->prepare( "SELECT order_item_type, order_item_id, order_id, order_item_name FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d ORDER BY order_item_id;", $order->get_id() )
+ );
+ foreach ( $items as $item ) {
+ wp_cache_set( 'item-' . $item->order_item_id, $item, 'order-items' );
+ }
+ if ( 0 < $order->get_id() ) {
+ wp_cache_set( 'order-items-' . $order->get_id(), $items, 'orders' );
+ }
+ }
+
+ $items = wp_list_filter( $items, array( 'order_item_type' => $type ) );
+
+ if ( ! empty( $items ) ) {
+ $items = array_map( array( 'WC_Order_Factory', 'get_order_item' ), array_combine( wp_list_pluck( $items, 'order_item_id' ), $items ) );
+ } else {
+ $items = array();
+ }
+
+ return $items;
+ }
+
+ /**
+ * Remove all line items (products, coupons, shipping, taxes) from the order.
+ *
+ * @param WC_Order $order Order object.
+ * @param string $type Order item type. Default null.
+ */
+ public function delete_items( $order, $type = null ) {
+ global $wpdb;
+ if ( ! empty( $type ) ) {
+ $wpdb->query( $wpdb->prepare( "DELETE FROM itemmeta USING {$wpdb->prefix}woocommerce_order_itemmeta itemmeta INNER JOIN {$wpdb->prefix}woocommerce_order_items items WHERE itemmeta.order_item_id = items.order_item_id AND items.order_id = %d AND items.order_item_type = %s", $order->get_id(), $type ) );
+ $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d AND order_item_type = %s", $order->get_id(), $type ) );
+ } else {
+ $wpdb->query( $wpdb->prepare( "DELETE FROM itemmeta USING {$wpdb->prefix}woocommerce_order_itemmeta itemmeta INNER JOIN {$wpdb->prefix}woocommerce_order_items items WHERE itemmeta.order_item_id = items.order_item_id and items.order_id = %d", $order->get_id() ) );
+ $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d", $order->get_id() ) );
+ }
+ $this->clear_caches( $order );
+ }
+
+ /**
+ * Get token ids for an order.
+ *
+ * @param WC_Order $order Order object.
+ * @return array
+ */
+ public function get_payment_token_ids( $order ) {
+ $token_ids = array_filter( (array) get_post_meta( $order->get_id(), '_payment_tokens', true ) );
+ return $token_ids;
+ }
+
+ /**
+ * Update token ids for an order.
+ *
+ * @param WC_Order $order Order object.
+ * @param array $token_ids Payment token ids.
+ */
+ public function update_payment_token_ids( $order, $token_ids ) {
+ update_post_meta( $order->get_id(), '_payment_tokens', $token_ids );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/abstract-wc-order-item-type-data-store.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/abstract-wc-order-item-type-data-store.php
new file mode 100644
index 0000000..0aa25a6
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/abstract-wc-order-item-type-data-store.php
@@ -0,0 +1,166 @@
+insert(
+ $wpdb->prefix . 'woocommerce_order_items',
+ array(
+ 'order_item_name' => $item->get_name(),
+ 'order_item_type' => $item->get_type(),
+ 'order_id' => $item->get_order_id(),
+ )
+ );
+ $item->set_id( $wpdb->insert_id );
+ $this->save_item_data( $item );
+ $item->save_meta_data();
+ $item->apply_changes();
+ $this->clear_cache( $item );
+
+ do_action( 'woocommerce_new_order_item', $item->get_id(), $item, $item->get_order_id() );
+ }
+
+ /**
+ * Update a order item in the database.
+ *
+ * @since 3.0.0
+ * @param WC_Order_Item $item Order item object.
+ */
+ public function update( &$item ) {
+ global $wpdb;
+
+ $changes = $item->get_changes();
+
+ if ( array_intersect( array( 'name', 'order_id' ), array_keys( $changes ) ) ) {
+ $wpdb->update(
+ $wpdb->prefix . 'woocommerce_order_items',
+ array(
+ 'order_item_name' => $item->get_name(),
+ 'order_item_type' => $item->get_type(),
+ 'order_id' => $item->get_order_id(),
+ ),
+ array( 'order_item_id' => $item->get_id() )
+ );
+ }
+
+ $this->save_item_data( $item );
+ $item->save_meta_data();
+ $item->apply_changes();
+ $this->clear_cache( $item );
+
+ do_action( 'woocommerce_update_order_item', $item->get_id(), $item, $item->get_order_id() );
+ }
+
+ /**
+ * Remove an order item from the database.
+ *
+ * @since 3.0.0
+ * @param WC_Order_Item $item Order item object.
+ * @param array $args Array of args to pass to the delete method.
+ */
+ public function delete( &$item, $args = array() ) {
+ if ( $item->get_id() ) {
+ global $wpdb;
+ do_action( 'woocommerce_before_delete_order_item', $item->get_id() );
+ $wpdb->delete( $wpdb->prefix . 'woocommerce_order_items', array( 'order_item_id' => $item->get_id() ) );
+ $wpdb->delete( $wpdb->prefix . 'woocommerce_order_itemmeta', array( 'order_item_id' => $item->get_id() ) );
+ do_action( 'woocommerce_delete_order_item', $item->get_id() );
+ $this->clear_cache( $item );
+ }
+ }
+
+ /**
+ * Read a order item from the database.
+ *
+ * @since 3.0.0
+ *
+ * @param WC_Order_Item $item Order item object.
+ *
+ * @throws Exception If invalid order item.
+ */
+ public function read( &$item ) {
+ global $wpdb;
+
+ $item->set_defaults();
+
+ // Get from cache if available.
+ $data = wp_cache_get( 'item-' . $item->get_id(), 'order-items' );
+
+ if ( false === $data ) {
+ $data = $wpdb->get_row( $wpdb->prepare( "SELECT order_id, order_item_name FROM {$wpdb->prefix}woocommerce_order_items WHERE order_item_id = %d LIMIT 1;", $item->get_id() ) );
+ wp_cache_set( 'item-' . $item->get_id(), $data, 'order-items' );
+ }
+
+ if ( ! $data ) {
+ throw new Exception( __( 'Invalid order item.', 'woocommerce' ) );
+ }
+
+ $item->set_props(
+ array(
+ 'order_id' => $data->order_id,
+ 'name' => $data->order_item_name,
+ )
+ );
+ $item->read_meta_data();
+ }
+
+ /**
+ * Saves an item's data to the database / item meta.
+ * Ran after both create and update, so $item->get_id() will be set.
+ *
+ * @since 3.0.0
+ * @param WC_Order_Item $item Order item object.
+ */
+ public function save_item_data( &$item ) {}
+
+ /**
+ * Clear meta cache.
+ *
+ * @param WC_Order_Item $item Order item object.
+ */
+ public function clear_cache( &$item ) {
+ wp_cache_delete( 'item-' . $item->get_id(), 'order-items' );
+ wp_cache_delete( 'order-items-' . $item->get_order_id(), 'orders' );
+ wp_cache_delete( $item->get_id(), $this->meta_type . '_meta' );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-coupon-data-store-cpt.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-coupon-data-store-cpt.php
new file mode 100644
index 0000000..8f9b731
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-coupon-data-store-cpt.php
@@ -0,0 +1,728 @@
+get_date_created( 'edit' ) ) {
+ $coupon->set_date_created( time() );
+ }
+
+ $coupon_id = wp_insert_post(
+ apply_filters(
+ 'woocommerce_new_coupon_data',
+ array(
+ 'post_type' => 'shop_coupon',
+ 'post_status' => 'publish',
+ 'post_author' => get_current_user_id(),
+ 'post_title' => $coupon->get_code( 'edit' ),
+ 'post_content' => '',
+ 'post_excerpt' => $coupon->get_description( 'edit' ),
+ 'post_date' => gmdate( 'Y-m-d H:i:s', $coupon->get_date_created()->getOffsetTimestamp() ),
+ 'post_date_gmt' => gmdate( 'Y-m-d H:i:s', $coupon->get_date_created()->getTimestamp() ),
+ )
+ ),
+ true
+ );
+
+ if ( $coupon_id ) {
+ $coupon->set_id( $coupon_id );
+ $this->update_post_meta( $coupon );
+ $coupon->save_meta_data();
+ $coupon->apply_changes();
+ delete_transient( 'rest_api_coupons_type_count' );
+ do_action( 'woocommerce_new_coupon', $coupon_id, $coupon );
+ }
+ }
+
+ /**
+ * Method to read a coupon.
+ *
+ * @since 3.0.0
+ *
+ * @param WC_Coupon $coupon Coupon object.
+ *
+ * @throws Exception If invalid coupon.
+ */
+ public function read( &$coupon ) {
+ $coupon->set_defaults();
+
+ $post_object = get_post( $coupon->get_id() );
+
+ if ( ! $coupon->get_id() || ! $post_object || 'shop_coupon' !== $post_object->post_type ) {
+ throw new Exception( __( 'Invalid coupon.', 'woocommerce' ) );
+ }
+
+ $coupon_id = $coupon->get_id();
+ $coupon->set_props(
+ array(
+ 'code' => $post_object->post_title,
+ 'description' => $post_object->post_excerpt,
+ 'date_created' => $this->string_to_timestamp( $post_object->post_date_gmt ),
+ 'date_modified' => $this->string_to_timestamp( $post_object->post_modified_gmt ),
+ 'date_expires' => metadata_exists( 'post', $coupon_id, 'date_expires' ) ? get_post_meta( $coupon_id, 'date_expires', true ) : get_post_meta( $coupon_id, 'expiry_date', true ), // @todo: Migrate expiry_date meta to date_expires in upgrade routine.
+ 'discount_type' => get_post_meta( $coupon_id, 'discount_type', true ),
+ 'amount' => get_post_meta( $coupon_id, 'coupon_amount', true ),
+ 'usage_count' => get_post_meta( $coupon_id, 'usage_count', true ),
+ 'individual_use' => 'yes' === get_post_meta( $coupon_id, 'individual_use', true ),
+ 'product_ids' => array_filter( (array) explode( ',', get_post_meta( $coupon_id, 'product_ids', true ) ) ),
+ 'excluded_product_ids' => array_filter( (array) explode( ',', get_post_meta( $coupon_id, 'exclude_product_ids', true ) ) ),
+ 'usage_limit' => get_post_meta( $coupon_id, 'usage_limit', true ),
+ 'usage_limit_per_user' => get_post_meta( $coupon_id, 'usage_limit_per_user', true ),
+ 'limit_usage_to_x_items' => 0 < get_post_meta( $coupon_id, 'limit_usage_to_x_items', true ) ? get_post_meta( $coupon_id, 'limit_usage_to_x_items', true ) : null,
+ 'free_shipping' => 'yes' === get_post_meta( $coupon_id, 'free_shipping', true ),
+ 'product_categories' => array_filter( (array) get_post_meta( $coupon_id, 'product_categories', true ) ),
+ 'excluded_product_categories' => array_filter( (array) get_post_meta( $coupon_id, 'exclude_product_categories', true ) ),
+ 'exclude_sale_items' => 'yes' === get_post_meta( $coupon_id, 'exclude_sale_items', true ),
+ 'minimum_amount' => get_post_meta( $coupon_id, 'minimum_amount', true ),
+ 'maximum_amount' => get_post_meta( $coupon_id, 'maximum_amount', true ),
+ 'email_restrictions' => array_filter( (array) get_post_meta( $coupon_id, 'customer_email', true ) ),
+ 'used_by' => array_filter( (array) get_post_meta( $coupon_id, '_used_by' ) ),
+ )
+ );
+ $coupon->read_meta_data();
+ $coupon->set_object_read( true );
+ do_action( 'woocommerce_coupon_loaded', $coupon );
+ }
+
+ /**
+ * Updates a coupon in the database.
+ *
+ * @since 3.0.0
+ * @param WC_Coupon $coupon Coupon object.
+ */
+ public function update( &$coupon ) {
+ $coupon->save_meta_data();
+ $changes = $coupon->get_changes();
+
+ if ( array_intersect( array( 'code', 'description', 'date_created', 'date_modified' ), array_keys( $changes ) ) ) {
+ $post_data = array(
+ 'post_title' => $coupon->get_code( 'edit' ),
+ 'post_excerpt' => $coupon->get_description( 'edit' ),
+ 'post_date' => gmdate( 'Y-m-d H:i:s', $coupon->get_date_created( 'edit' )->getOffsetTimestamp() ),
+ 'post_date_gmt' => gmdate( 'Y-m-d H:i:s', $coupon->get_date_created( 'edit' )->getTimestamp() ),
+ 'post_modified' => isset( $changes['date_modified'] ) ? gmdate( 'Y-m-d H:i:s', $coupon->get_date_modified( 'edit' )->getOffsetTimestamp() ) : current_time( 'mysql' ),
+ 'post_modified_gmt' => isset( $changes['date_modified'] ) ? gmdate( 'Y-m-d H:i:s', $coupon->get_date_modified( 'edit' )->getTimestamp() ) : current_time( 'mysql', 1 ),
+ );
+
+ /**
+ * When updating this object, to prevent infinite loops, use $wpdb
+ * to update data, since wp_update_post spawns more calls to the
+ * save_post action.
+ *
+ * This ensures hooks are fired by either WP itself (admin screen save),
+ * or an update purely from CRUD.
+ */
+ if ( doing_action( 'save_post' ) ) {
+ $GLOBALS['wpdb']->update( $GLOBALS['wpdb']->posts, $post_data, array( 'ID' => $coupon->get_id() ) );
+ clean_post_cache( $coupon->get_id() );
+ } else {
+ wp_update_post( array_merge( array( 'ID' => $coupon->get_id() ), $post_data ) );
+ }
+ $coupon->read_meta_data( true ); // Refresh internal meta data, in case things were hooked into `save_post` or another WP hook.
+ }
+ $this->update_post_meta( $coupon );
+ $coupon->apply_changes();
+ delete_transient( 'rest_api_coupons_type_count' );
+ do_action( 'woocommerce_update_coupon', $coupon->get_id(), $coupon );
+ }
+
+ /**
+ * Deletes a coupon from the database.
+ *
+ * @since 3.0.0
+ *
+ * @param WC_Coupon $coupon Coupon object.
+ * @param array $args Array of args to pass to the delete method.
+ */
+ public function delete( &$coupon, $args = array() ) {
+ $args = wp_parse_args(
+ $args,
+ array(
+ 'force_delete' => false,
+ )
+ );
+
+ $id = $coupon->get_id();
+
+ if ( ! $id ) {
+ return;
+ }
+
+ if ( $args['force_delete'] ) {
+ wp_delete_post( $id );
+
+ wp_cache_delete( WC_Cache_Helper::get_cache_prefix( 'coupons' ) . 'coupon_id_from_code_' . $coupon->get_code(), 'coupons' );
+
+ $coupon->set_id( 0 );
+ do_action( 'woocommerce_delete_coupon', $id );
+ } else {
+ wp_trash_post( $id );
+ do_action( 'woocommerce_trash_coupon', $id );
+ }
+ }
+
+ /**
+ * Helper method that updates all the post meta for a coupon based on it's settings in the WC_Coupon class.
+ *
+ * @param WC_Coupon $coupon Coupon object.
+ * @since 3.0.0
+ */
+ private function update_post_meta( &$coupon ) {
+ $meta_key_to_props = array(
+ 'discount_type' => 'discount_type',
+ 'coupon_amount' => 'amount',
+ 'individual_use' => 'individual_use',
+ 'product_ids' => 'product_ids',
+ 'exclude_product_ids' => 'excluded_product_ids',
+ 'usage_limit' => 'usage_limit',
+ 'usage_limit_per_user' => 'usage_limit_per_user',
+ 'limit_usage_to_x_items' => 'limit_usage_to_x_items',
+ 'usage_count' => 'usage_count',
+ 'date_expires' => 'date_expires',
+ 'free_shipping' => 'free_shipping',
+ 'product_categories' => 'product_categories',
+ 'exclude_product_categories' => 'excluded_product_categories',
+ 'exclude_sale_items' => 'exclude_sale_items',
+ 'minimum_amount' => 'minimum_amount',
+ 'maximum_amount' => 'maximum_amount',
+ 'customer_email' => 'email_restrictions',
+ );
+
+ $props_to_update = $this->get_props_to_update( $coupon, $meta_key_to_props );
+ foreach ( $props_to_update as $meta_key => $prop ) {
+ $value = $coupon->{"get_$prop"}( 'edit' );
+ $value = is_string( $value ) ? wp_slash( $value ) : $value;
+ switch ( $prop ) {
+ case 'individual_use':
+ case 'free_shipping':
+ case 'exclude_sale_items':
+ $value = wc_bool_to_string( $value );
+ break;
+ case 'product_ids':
+ case 'excluded_product_ids':
+ $value = implode( ',', array_filter( array_map( 'intval', $value ) ) );
+ break;
+ case 'product_categories':
+ case 'excluded_product_categories':
+ $value = array_filter( array_map( 'intval', $value ) );
+ break;
+ case 'email_restrictions':
+ $value = array_filter( array_map( 'sanitize_email', $value ) );
+ break;
+ case 'date_expires':
+ $value = $value ? $value->getTimestamp() : null;
+ break;
+ }
+
+ $updated = $this->update_or_delete_post_meta( $coupon, $meta_key, $value );
+
+ if ( $updated ) {
+ $this->updated_props[] = $prop;
+ }
+ }
+
+ do_action( 'woocommerce_coupon_object_updated_props', $coupon, $this->updated_props );
+ }
+
+ /**
+ * Increase usage count for current coupon.
+ *
+ * @since 3.0.0
+ * @param WC_Coupon $coupon Coupon object.
+ * @param string $used_by Either user ID or billing email.
+ * @param WC_Order $order (Optional) If passed, clears the hold record associated with order.
+
+ * @return int New usage count.
+ */
+ public function increase_usage_count( &$coupon, $used_by = '', $order = null ) {
+ $coupon_held_key_for_user = '';
+ if ( $order instanceof WC_Order ) {
+ $coupon_held_key_for_user = $order->get_data_store()->get_coupon_held_keys_for_users( $order, $coupon->get_id() );
+ }
+
+ $new_count = $this->update_usage_count_meta( $coupon, 'increase' );
+
+ if ( $used_by ) {
+ $this->add_coupon_used_by( $coupon, $used_by, $coupon_held_key_for_user );
+ $coupon->set_used_by( (array) get_post_meta( $coupon->get_id(), '_used_by' ) );
+ }
+
+ do_action( 'woocommerce_increase_coupon_usage_count', $coupon, $new_count, $used_by );
+
+ return $new_count;
+ }
+
+ /**
+ * Helper function to add a `_used_by` record to track coupons used by the user.
+ *
+ * @param WC_Coupon $coupon Coupon object.
+ * @param string $used_by Either user ID or billing email.
+ * @param string $coupon_held_key (Optional) Update meta key to `_used_by` instead of adding a new record.
+ */
+ private function add_coupon_used_by( $coupon, $used_by, $coupon_held_key ) {
+ global $wpdb;
+ if ( $coupon_held_key && '' !== $coupon_held_key ) {
+ // Looks like we added a tentative record for this coupon getting used.
+ // Lets change the tentative record to a permanent one.
+ $result = $wpdb->query(
+ $wpdb->prepare(
+ "
+ UPDATE $wpdb->postmeta SET meta_key = %s, meta_value = %s WHERE meta_key = %s LIMIT 1",
+ '_used_by',
+ $used_by,
+ $coupon_held_key
+ )
+ );
+ if ( ! $result ) {
+ // If no rows were updated, then insert a `_used_by` row manually to maintain consistency.
+ add_post_meta( $coupon->get_id(), '_used_by', strtolower( $used_by ) );
+ }
+ } else {
+ add_post_meta( $coupon->get_id(), '_used_by', strtolower( $used_by ) );
+ }
+ }
+
+ /**
+ * Decrease usage count for current coupon.
+ *
+ * @since 3.0.0
+ * @param WC_Coupon $coupon Coupon object.
+ * @param string $used_by Either user ID or billing email.
+ * @return int New usage count.
+ */
+ public function decrease_usage_count( &$coupon, $used_by = '' ) {
+ global $wpdb;
+ $new_count = $this->update_usage_count_meta( $coupon, 'decrease' );
+ if ( $used_by ) {
+ /**
+ * We're doing this the long way because `delete_post_meta( $id, $key, $value )` deletes.
+ * all instances where the key and value match, and we only want to delete one.
+ */
+ $meta_id = $wpdb->get_var(
+ $wpdb->prepare(
+ "SELECT meta_id FROM $wpdb->postmeta WHERE meta_key = '_used_by' AND meta_value = %s AND post_id = %d LIMIT 1;",
+ $used_by,
+ $coupon->get_id()
+ )
+ );
+ if ( $meta_id ) {
+ delete_metadata_by_mid( 'post', $meta_id );
+ $coupon->set_used_by( (array) get_post_meta( $coupon->get_id(), '_used_by' ) );
+ }
+ }
+
+ do_action( 'woocommerce_decrease_coupon_usage_count', $coupon, $new_count, $used_by );
+
+ return $new_count;
+ }
+
+ /**
+ * Increase or decrease the usage count for a coupon by 1.
+ *
+ * @since 3.0.0
+ * @param WC_Coupon $coupon Coupon object.
+ * @param string $operation 'increase' or 'decrease'.
+ * @return int New usage count
+ */
+ private function update_usage_count_meta( &$coupon, $operation = 'increase' ) {
+ global $wpdb;
+ $id = $coupon->get_id();
+ $operator = ( 'increase' === $operation ) ? '+' : '-';
+
+ add_post_meta( $id, 'usage_count', $coupon->get_usage_count( 'edit' ), true );
+ $wpdb->query(
+ $wpdb->prepare(
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
+ "UPDATE $wpdb->postmeta SET meta_value = meta_value {$operator} 1 WHERE meta_key = 'usage_count' AND post_id = %d;",
+ $id
+ )
+ );
+
+ // Get the latest value direct from the DB, instead of possibly the WP meta cache.
+ return (int) $wpdb->get_var( $wpdb->prepare( "SELECT meta_value FROM $wpdb->postmeta WHERE meta_key = 'usage_count' AND post_id = %d;", $id ) );
+ }
+
+ /**
+ * Returns tentative usage count for coupon.
+ *
+ * @param int $coupon_id Coupon ID.
+ *
+ * @return int Tentative usage count.
+ */
+ public function get_tentative_usage_count( $coupon_id ) {
+ global $wpdb;
+ return $wpdb->get_var(
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
+ $this->get_tentative_usage_query( $coupon_id )
+ );
+ }
+ /**
+ * Get the number of uses for a coupon by user ID.
+ *
+ * @since 3.0.0
+ * @param WC_Coupon $coupon Coupon object.
+ * @param id $user_id User ID.
+ * @return int
+ */
+ public function get_usage_by_user_id( &$coupon, $user_id ) {
+ global $wpdb;
+ $usage_count = $wpdb->get_var(
+ $wpdb->prepare(
+ "SELECT COUNT( meta_id ) FROM {$wpdb->postmeta} WHERE post_id = %d AND meta_key = '_used_by' AND meta_value = %d;",
+ $coupon->get_id(),
+ $user_id
+ )
+ );
+ $tentative_usage_count = $this->get_tentative_usages_for_user( $coupon->get_id(), array( $user_id ) );
+ return $tentative_usage_count + $usage_count;
+ }
+
+ /**
+ * Get the number of uses for a coupon by email address
+ *
+ * @since 3.6.4
+ * @param WC_Coupon $coupon Coupon object.
+ * @param string $email Email address.
+ * @return int
+ */
+ public function get_usage_by_email( &$coupon, $email ) {
+ global $wpdb;
+ $usage_count = $wpdb->get_var(
+ $wpdb->prepare(
+ "SELECT COUNT( meta_id ) FROM {$wpdb->postmeta} WHERE post_id = %d AND meta_key = '_used_by' AND meta_value = %s;",
+ $coupon->get_id(),
+ $email
+ )
+ );
+ $tentative_usage_count = $this->get_tentative_usages_for_user( $coupon->get_id(), array( $email ) );
+ return $tentative_usage_count + $usage_count;
+ }
+
+ /**
+ * Get tentative coupon usages for user.
+ *
+ * @param int $coupon_id Coupon ID.
+ * @param array $user_aliases Array of user aliases to check tentative usages for.
+ *
+ * @return string|null
+ */
+ public function get_tentative_usages_for_user( $coupon_id, $user_aliases ) {
+ global $wpdb;
+ return $wpdb->get_var(
+ $this->get_tentative_usage_query_for_user( $coupon_id, $user_aliases )
+ ); // WPCS: unprepared SQL ok.
+
+ }
+
+ /**
+ * Get held time for resources before cancelling the order. Use 60 minutes as sane default.
+ * Note that the filter `woocommerce_coupon_hold_minutes` only support minutes because it's getting used elsewhere as well, however this function returns in seconds.
+ *
+ * @return int
+ */
+ private function get_tentative_held_time() {
+ return apply_filters( 'woocommerce_coupon_hold_minutes', ( (int) get_option( 'woocommerce_hold_stock_minutes', 60 ) ) ) * 60;
+ }
+
+ /**
+ * Check and records coupon usage tentatively for short period of time so that counts validation is correct. Returns early if there is no limit defined for the coupon.
+ *
+ * @param WC_Coupon $coupon Coupon object.
+ *
+ * @return bool|int|string|null Returns meta key if coupon was held, null if returned early.
+ */
+ public function check_and_hold_coupon( $coupon ) {
+ global $wpdb;
+
+ $usage_limit = $coupon->get_usage_limit();
+ $held_time = $this->get_tentative_held_time();
+
+ if ( 0 >= $usage_limit || 0 >= $held_time ) {
+ return null;
+ }
+
+ if ( ! apply_filters( 'woocommerce_hold_stock_for_checkout', true ) ) {
+ return null;
+ }
+
+ // Make sure we have usage_count meta key for this coupon because its required for `$query_for_usages`.
+ // We are not directly modifying `$query_for_usages` to allow for `usage_count` not present only keep that query simple.
+ if ( ! metadata_exists( 'post', $coupon->get_id(), 'usage_count' ) ) {
+ $coupon->set_usage_count( $coupon->get_usage_count() ); // Use `get_usage_count` here to write default value, which may changed by a filter.
+ $coupon->save();
+ }
+
+ $query_for_usages = $wpdb->prepare(
+ "
+ SELECT meta_value from $wpdb->postmeta
+ WHERE {$wpdb->postmeta}.meta_key = 'usage_count'
+ AND {$wpdb->postmeta}.post_id = %d
+ LIMIT 1
+ FOR UPDATE
+ ",
+ $coupon->get_id()
+ );
+
+ $query_for_tentative_usages = $this->get_tentative_usage_query( $coupon->get_id() );
+ $db_timestamp = $wpdb->get_var( 'SELECT UNIX_TIMESTAMP() FROM DUAL' );
+
+ $coupon_usage_key = '_coupon_held_' . ( (int) $db_timestamp + $held_time ) . '_' . wp_generate_password( 6, false );
+
+ $insert_statement = $wpdb->prepare(
+ "
+ INSERT INTO $wpdb->postmeta ( post_id, meta_key, meta_value )
+ SELECT %d, %s, %s FROM DUAL
+ WHERE ( $query_for_usages ) + ( $query_for_tentative_usages ) < %d
+ ",
+ $coupon->get_id(),
+ $coupon_usage_key,
+ '',
+ $usage_limit
+ ); // WPCS: unprepared SQL ok.
+
+ /**
+ * In some cases, specifically when there is a combined index on post_id,meta_key, the insert statement above could end up in a deadlock.
+ * We will try to insert 3 times before giving up to recover from deadlock.
+ */
+ for ( $count = 0; $count < 3; $count++ ) {
+ $result = $wpdb->query( $insert_statement ); // WPCS: unprepared SQL ok.
+ if ( false !== $result ) {
+ break;
+ }
+ }
+
+ return $result > 0 ? $coupon_usage_key : $result;
+ }
+
+ /**
+ * Generate query to calculate tentative usages for the coupon.
+ *
+ * @param int $coupon_id Coupon ID to get tentative usage query for.
+ *
+ * @return string Query for tentative usages.
+ */
+ private function get_tentative_usage_query( $coupon_id ) {
+ global $wpdb;
+ return $wpdb->prepare(
+ "
+ SELECT COUNT(meta_id) FROM $wpdb->postmeta
+ WHERE {$wpdb->postmeta}.meta_key like %s
+ AND {$wpdb->postmeta}.meta_key > %s
+ AND {$wpdb->postmeta}.post_id = %d
+ FOR UPDATE
+ ",
+ array(
+ '_coupon_held_%',
+ '_coupon_held_' . time(),
+ $coupon_id,
+ )
+ ); // WPCS: unprepared SQL ok.
+ }
+
+ /**
+ * Check and records coupon usage tentatively for passed user aliases for short period of time so that counts validation is correct. Returns early if there is no limit per user for the coupon.
+ *
+ * @param WC_Coupon $coupon Coupon object.
+ * @param array $user_aliases Emails or Ids to check for user.
+ * @param string $user_alias Email/ID to use as `used_by` value.
+ *
+ * @return null|false|int
+ */
+ public function check_and_hold_coupon_for_user( $coupon, $user_aliases, $user_alias ) {
+ global $wpdb;
+ $limit_per_user = $coupon->get_usage_limit_per_user();
+ $held_time = $this->get_tentative_held_time();
+
+ if ( 0 >= $limit_per_user || 0 >= $held_time ) {
+ // This coupon do not have any restriction for usage per customer. No need to check further, lets bail.
+ return null;
+ }
+
+ if ( ! apply_filters( 'woocommerce_hold_stock_for_checkout', true ) ) {
+ return null;
+ }
+
+ $format = implode( "','", array_fill( 0, count( $user_aliases ), '%s' ) );
+
+ $query_for_usages = $wpdb->prepare(
+ "
+ SELECT COUNT(*) FROM $wpdb->postmeta
+ WHERE {$wpdb->postmeta}.meta_key = '_used_by'
+ AND {$wpdb->postmeta}.meta_value IN ('$format')
+ AND {$wpdb->postmeta}.post_id = %d
+ FOR UPDATE
+ ",
+ array_merge(
+ $user_aliases,
+ array( $coupon->get_id() )
+ )
+ ); // WPCS: unprepared SQL ok.
+
+ $query_for_tentative_usages = $this->get_tentative_usage_query_for_user( $coupon->get_id(), $user_aliases );
+ $db_timestamp = $wpdb->get_var( 'SELECT UNIX_TIMESTAMP() FROM DUAL' );
+
+ $coupon_used_by_meta_key = '_maybe_used_by_' . ( (int) $db_timestamp + $held_time ) . '_' . wp_generate_password( 6, false );
+ $insert_statement = $wpdb->prepare(
+ "
+ INSERT INTO $wpdb->postmeta ( post_id, meta_key, meta_value )
+ SELECT %d, %s, %s FROM DUAL
+ WHERE ( $query_for_usages ) + ( $query_for_tentative_usages ) < %d
+ ",
+ $coupon->get_id(),
+ $coupon_used_by_meta_key,
+ $user_alias,
+ $limit_per_user
+ ); // WPCS: unprepared SQL ok.
+
+ // This query can potentially be deadlocked if a combined index on post_id and meta_key is present and there is
+ // high concurrency, in which case DB will abort the query which has done less work to resolve deadlock.
+ // We will try up to 3 times before giving up.
+ for ( $count = 0; $count < 3; $count++ ) {
+ $result = $wpdb->query( $insert_statement ); // WPCS: unprepared SQL ok.
+ if ( false !== $result ) {
+ break;
+ }
+ }
+
+ return $result > 0 ? $coupon_used_by_meta_key : $result;
+ }
+
+ /**
+ * Generate query to calculate tentative usages for the coupon by the user.
+ *
+ * @param int $coupon_id Coupon ID.
+ * @param array $user_aliases List of user aliases to check for usages.
+ *
+ * @return string Tentative usages query.
+ */
+ private function get_tentative_usage_query_for_user( $coupon_id, $user_aliases ) {
+ global $wpdb;
+
+ $format = implode( "','", array_fill( 0, count( $user_aliases ), '%s' ) );
+
+ // Note that if you are debugging, `_maybe_used_by_%` will be converted to `_maybe_used_by_{...very long str...}` to very long string. This is expected, and is automatically corrected while running the insert query.
+ return $wpdb->prepare(
+ "
+ SELECT COUNT( meta_id ) FROM $wpdb->postmeta
+ WHERE {$wpdb->postmeta}.meta_key like %s
+ AND {$wpdb->postmeta}.meta_key > %s
+ AND {$wpdb->postmeta}.post_id = %d
+ AND {$wpdb->postmeta}.meta_value IN ('$format')
+ FOR UPDATE
+ ",
+ array_merge(
+ array(
+ '_maybe_used_by_%',
+ '_maybe_used_by_' . time(),
+ $coupon_id,
+ ),
+ $user_aliases
+ )
+ ); // WPCS: unprepared SQL ok.
+ }
+
+ /**
+ * Return a coupon code for a specific ID.
+ *
+ * @since 3.0.0
+ * @param int $id Coupon ID.
+ * @return string Coupon Code
+ */
+ public function get_code_by_id( $id ) {
+ global $wpdb;
+ return $wpdb->get_var(
+ $wpdb->prepare(
+ "SELECT post_title
+ FROM $wpdb->posts
+ WHERE ID = %d
+ AND post_type = 'shop_coupon'
+ AND post_status = 'publish'",
+ $id
+ )
+ );
+ }
+
+ /**
+ * Return an array of IDs for for a specific coupon code.
+ * Can return multiple to check for existence.
+ *
+ * @since 3.0.0
+ * @param string $code Coupon code.
+ * @return array Array of IDs.
+ */
+ public function get_ids_by_code( $code ) {
+ global $wpdb;
+ return $wpdb->get_col(
+ $wpdb->prepare(
+ "SELECT ID FROM $wpdb->posts WHERE post_title = %s AND post_type = 'shop_coupon' AND post_status = 'publish' ORDER BY post_date DESC",
+ wc_sanitize_coupon_code( $code )
+ )
+ );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-customer-data-store-session.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-customer-data-store-session.php
new file mode 100644
index 0000000..4a2585d
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-customer-data-store-session.php
@@ -0,0 +1,197 @@
+save_to_session( $customer );
+ }
+
+ /**
+ * Simply update the session.
+ *
+ * @param WC_Customer $customer Customer object.
+ */
+ public function update( &$customer ) {
+ $this->save_to_session( $customer );
+ }
+
+ /**
+ * Saves all customer data to the session.
+ *
+ * @param WC_Customer $customer Customer object.
+ */
+ public function save_to_session( $customer ) {
+ $data = array();
+ foreach ( $this->session_keys as $session_key ) {
+ $function_key = $session_key;
+ if ( 'billing_' === substr( $session_key, 0, 8 ) ) {
+ $session_key = str_replace( 'billing_', '', $session_key );
+ }
+ $data[ $session_key ] = (string) $customer->{"get_$function_key"}( 'edit' );
+ }
+ WC()->session->set( 'customer', $data );
+ }
+
+ /**
+ * Read customer data from the session unless the user has logged in, in
+ * which case the stored ID will differ from the actual ID.
+ *
+ * @since 3.0.0
+ * @param WC_Customer $customer Customer object.
+ */
+ public function read( &$customer ) {
+ $data = (array) WC()->session->get( 'customer' );
+
+ /**
+ * There is a valid session if $data is not empty, and the ID matches the logged in user ID.
+ *
+ * If the user object has been updated since the session was created (based on date_modified) we should not load the session - data should be reloaded.
+ */
+ if ( isset( $data['id'], $data['date_modified'] ) && $data['id'] === (string) $customer->get_id() && $data['date_modified'] === (string) $customer->get_date_modified( 'edit' ) ) {
+ foreach ( $this->session_keys as $session_key ) {
+ if ( in_array( $session_key, array( 'id', 'date_modified' ), true ) ) {
+ continue;
+ }
+ $function_key = $session_key;
+ if ( 'billing_' === substr( $session_key, 0, 8 ) ) {
+ $session_key = str_replace( 'billing_', '', $session_key );
+ }
+ if ( isset( $data[ $session_key ] ) && is_callable( array( $customer, "set_{$function_key}" ) ) ) {
+ $customer->{"set_{$function_key}"}( wp_unslash( $data[ $session_key ] ) );
+ }
+ }
+ }
+ $this->set_defaults( $customer );
+ $customer->set_object_read( true );
+ }
+
+ /**
+ * Load default values if props are unset.
+ *
+ * @param WC_Customer $customer Customer object.
+ */
+ protected function set_defaults( &$customer ) {
+ try {
+ $default = wc_get_customer_default_location();
+
+ if ( ! $customer->get_billing_country() ) {
+ $customer->set_billing_country( $default['country'] );
+ }
+
+ if ( ! $customer->get_shipping_country() ) {
+ $customer->set_shipping_country( $customer->get_billing_country() );
+ }
+
+ if ( ! $customer->get_billing_state() ) {
+ $customer->set_billing_state( $default['state'] );
+ }
+
+ if ( ! $customer->get_shipping_state() ) {
+ $customer->set_shipping_state( $customer->get_billing_state() );
+ }
+
+ if ( ! $customer->get_billing_email() && is_user_logged_in() ) {
+ $current_user = wp_get_current_user();
+ $customer->set_billing_email( $current_user->user_email );
+ }
+ } catch ( WC_Data_Exception $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
+ }
+ }
+
+ /**
+ * Deletes a customer from the database.
+ *
+ * @since 3.0.0
+ * @param WC_Customer $customer Customer object.
+ * @param array $args Array of args to pass to the delete method.
+ */
+ public function delete( &$customer, $args = array() ) {
+ WC()->session->set( 'customer', null );
+ }
+
+ /**
+ * Gets the customers last order.
+ *
+ * @since 3.0.0
+ * @param WC_Customer $customer Customer object.
+ * @return WC_Order|false
+ */
+ public function get_last_order( &$customer ) {
+ return false;
+ }
+
+ /**
+ * Return the number of orders this customer has.
+ *
+ * @since 3.0.0
+ * @param WC_Customer $customer Customer object.
+ * @return integer
+ */
+ public function get_order_count( &$customer ) {
+ return 0;
+ }
+
+ /**
+ * Return how much money this customer has spent.
+ *
+ * @since 3.0.0
+ * @param WC_Customer $customer Customer object.
+ * @return float
+ */
+ public function get_total_spent( &$customer ) {
+ return 0;
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-customer-data-store.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-customer-data-store.php
new file mode 100644
index 0000000..a772e45
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-customer-data-store.php
@@ -0,0 +1,512 @@
+prefix ? $wpdb->prefix : 'wp_';
+
+ return ! in_array( $meta->meta_key, $this->internal_meta_keys, true )
+ && 0 !== strpos( $meta->meta_key, '_woocommerce_persistent_cart' )
+ && 0 !== strpos( $meta->meta_key, 'closedpostboxes_' )
+ && 0 !== strpos( $meta->meta_key, 'metaboxhidden_' )
+ && 0 !== strpos( $meta->meta_key, 'manageedit-' )
+ && ! strstr( $meta->meta_key, $table_prefix )
+ && 0 !== stripos( $meta->meta_key, 'wp_' );
+ }
+
+ /**
+ * Method to create a new customer in the database.
+ *
+ * @since 3.0.0
+ *
+ * @param WC_Customer $customer Customer object.
+ *
+ * @throws WC_Data_Exception If unable to create new customer.
+ */
+ public function create( &$customer ) {
+ $id = wc_create_new_customer( $customer->get_email(), $customer->get_username(), $customer->get_password() );
+
+ if ( is_wp_error( $id ) ) {
+ throw new WC_Data_Exception( $id->get_error_code(), $id->get_error_message() );
+ }
+
+ $customer->set_id( $id );
+ $this->update_user_meta( $customer );
+
+ // Prevent wp_update_user calls in the same request and customer trigger the 'Notice of Password Changed' email.
+ $customer->set_password( '' );
+
+ wp_update_user(
+ apply_filters(
+ 'woocommerce_update_customer_args',
+ array(
+ 'ID' => $customer->get_id(),
+ 'role' => $customer->get_role(),
+ 'display_name' => $customer->get_display_name(),
+ ),
+ $customer
+ )
+ );
+ $wp_user = new WP_User( $customer->get_id() );
+ $customer->set_date_created( $wp_user->user_registered );
+ $customer->set_date_modified( get_user_meta( $customer->get_id(), 'last_update', true ) );
+ $customer->save_meta_data();
+ $customer->apply_changes();
+ do_action( 'woocommerce_new_customer', $customer->get_id(), $customer );
+ }
+
+ /**
+ * Method to read a customer object.
+ *
+ * @since 3.0.0
+ * @param WC_Customer $customer Customer object.
+ * @throws Exception If invalid customer.
+ */
+ public function read( &$customer ) {
+ $user_object = $customer->get_id() ? get_user_by( 'id', $customer->get_id() ) : false;
+
+ // User object is required.
+ if ( ! $user_object || empty( $user_object->ID ) ) {
+ throw new Exception( __( 'Invalid customer.', 'woocommerce' ) );
+ }
+
+ $customer_id = $customer->get_id();
+
+ // Load meta but exclude deprecated props.
+ $user_meta = array_diff_key(
+ array_change_key_case( array_map( 'wc_flatten_meta_callback', get_user_meta( $customer_id ) ) ),
+ array_flip( array( 'country', 'state', 'postcode', 'city', 'address', 'address_2', 'default', 'location' ) )
+ );
+
+ $customer->set_props( $user_meta );
+ $customer->set_props(
+ array(
+ 'is_paying_customer' => get_user_meta( $customer_id, 'paying_customer', true ),
+ 'email' => $user_object->user_email,
+ 'username' => $user_object->user_login,
+ 'display_name' => $user_object->display_name,
+ 'date_created' => $user_object->user_registered, // Mysql string in local format.
+ 'date_modified' => get_user_meta( $customer_id, 'last_update', true ),
+ 'role' => ! empty( $user_object->roles[0] ) ? $user_object->roles[0] : 'customer',
+ )
+ );
+ $customer->read_meta_data();
+ $customer->set_object_read( true );
+ do_action( 'woocommerce_customer_loaded', $customer );
+ }
+
+ /**
+ * Updates a customer in the database.
+ *
+ * @since 3.0.0
+ * @param WC_Customer $customer Customer object.
+ */
+ public function update( &$customer ) {
+ wp_update_user(
+ apply_filters(
+ 'woocommerce_update_customer_args',
+ array(
+ 'ID' => $customer->get_id(),
+ 'user_email' => $customer->get_email(),
+ 'display_name' => $customer->get_display_name(),
+ ),
+ $customer
+ )
+ );
+
+ // Only update password if a new one was set with set_password.
+ if ( $customer->get_password() ) {
+ wp_update_user(
+ array(
+ 'ID' => $customer->get_id(),
+ 'user_pass' => $customer->get_password(),
+ )
+ );
+ $customer->set_password( '' );
+ }
+
+ $this->update_user_meta( $customer );
+ $customer->set_date_modified( get_user_meta( $customer->get_id(), 'last_update', true ) );
+ $customer->save_meta_data();
+ $customer->apply_changes();
+ do_action( 'woocommerce_update_customer', $customer->get_id(), $customer );
+ }
+
+ /**
+ * Deletes a customer from the database.
+ *
+ * @since 3.0.0
+ * @param WC_Customer $customer Customer object.
+ * @param array $args Array of args to pass to the delete method.
+ */
+ public function delete( &$customer, $args = array() ) {
+ if ( ! $customer->get_id() ) {
+ return;
+ }
+
+ $args = wp_parse_args(
+ $args,
+ array(
+ 'reassign' => 0,
+ )
+ );
+
+ $id = $customer->get_id();
+ wp_delete_user( $id, $args['reassign'] );
+
+ do_action( 'woocommerce_delete_customer', $id );
+ }
+
+ /**
+ * Helper method that updates all the meta for a customer. Used for update & create.
+ *
+ * @since 3.0.0
+ * @param WC_Customer $customer Customer object.
+ */
+ private function update_user_meta( $customer ) {
+ $updated_props = array();
+ $changed_props = $customer->get_changes();
+
+ $meta_key_to_props = array(
+ 'paying_customer' => 'is_paying_customer',
+ 'first_name' => 'first_name',
+ 'last_name' => 'last_name',
+ );
+
+ foreach ( $meta_key_to_props as $meta_key => $prop ) {
+ if ( ! array_key_exists( $prop, $changed_props ) ) {
+ continue;
+ }
+
+ if ( update_user_meta( $customer->get_id(), $meta_key, $customer->{"get_$prop"}( 'edit' ) ) ) {
+ $updated_props[] = $prop;
+ }
+ }
+
+ $billing_address_props = array(
+ 'billing_first_name' => 'billing_first_name',
+ 'billing_last_name' => 'billing_last_name',
+ 'billing_company' => 'billing_company',
+ 'billing_address_1' => 'billing_address_1',
+ 'billing_address_2' => 'billing_address_2',
+ 'billing_city' => 'billing_city',
+ 'billing_state' => 'billing_state',
+ 'billing_postcode' => 'billing_postcode',
+ 'billing_country' => 'billing_country',
+ 'billing_email' => 'billing_email',
+ 'billing_phone' => 'billing_phone',
+ );
+
+ foreach ( $billing_address_props as $meta_key => $prop ) {
+ $prop_key = substr( $prop, 8 );
+
+ if ( ! isset( $changed_props['billing'] ) || ! array_key_exists( $prop_key, $changed_props['billing'] ) ) {
+ continue;
+ }
+
+ if ( update_user_meta( $customer->get_id(), $meta_key, $customer->{"get_$prop"}( 'edit' ) ) ) {
+ $updated_props[] = $prop;
+ }
+ }
+
+ $shipping_address_props = array(
+ 'shipping_first_name' => 'shipping_first_name',
+ 'shipping_last_name' => 'shipping_last_name',
+ 'shipping_company' => 'shipping_company',
+ 'shipping_address_1' => 'shipping_address_1',
+ 'shipping_address_2' => 'shipping_address_2',
+ 'shipping_city' => 'shipping_city',
+ 'shipping_state' => 'shipping_state',
+ 'shipping_postcode' => 'shipping_postcode',
+ 'shipping_country' => 'shipping_country',
+ );
+
+ foreach ( $shipping_address_props as $meta_key => $prop ) {
+ $prop_key = substr( $prop, 9 );
+
+ if ( ! isset( $changed_props['shipping'] ) || ! array_key_exists( $prop_key, $changed_props['shipping'] ) ) {
+ continue;
+ }
+
+ if ( update_user_meta( $customer->get_id(), $meta_key, $customer->{"get_$prop"}( 'edit' ) ) ) {
+ $updated_props[] = $prop;
+ }
+ }
+
+ do_action( 'woocommerce_customer_object_updated_props', $customer, $updated_props );
+ }
+
+ /**
+ * Gets the customers last order.
+ *
+ * @since 3.0.0
+ * @param WC_Customer $customer Customer object.
+ * @return WC_Order|false
+ */
+ public function get_last_order( &$customer ) {
+ global $wpdb;
+
+ $last_order = $wpdb->get_var(
+ // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
+ "SELECT posts.ID
+ FROM $wpdb->posts AS posts
+ LEFT JOIN {$wpdb->postmeta} AS meta on posts.ID = meta.post_id
+ WHERE meta.meta_key = '_customer_user'
+ AND meta.meta_value = '" . esc_sql( $customer->get_id() ) . "'
+ AND posts.post_type = 'shop_order'
+ AND posts.post_status IN ( '" . implode( "','", array_map( 'esc_sql', array_keys( wc_get_order_statuses() ) ) ) . "' )
+ ORDER BY posts.ID DESC"
+ // phpcs:enable
+ );
+
+ if ( ! $last_order ) {
+ return false;
+ }
+
+ return wc_get_order( absint( $last_order ) );
+ }
+
+ /**
+ * Return the number of orders this customer has.
+ *
+ * @since 3.0.0
+ * @param WC_Customer $customer Customer object.
+ * @return integer
+ */
+ public function get_order_count( &$customer ) {
+ $count = get_user_meta( $customer->get_id(), '_order_count', true );
+
+ if ( '' === $count ) {
+ global $wpdb;
+
+ $count = $wpdb->get_var(
+ // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
+ "SELECT COUNT(*)
+ FROM $wpdb->posts as posts
+ LEFT JOIN {$wpdb->postmeta} AS meta ON posts.ID = meta.post_id
+ WHERE meta.meta_key = '_customer_user'
+ AND posts.post_type = 'shop_order'
+ AND posts.post_status IN ( '" . implode( "','", array_map( 'esc_sql', array_keys( wc_get_order_statuses() ) ) ) . "' )
+ AND meta_value = '" . esc_sql( $customer->get_id() ) . "'"
+ // phpcs:enable
+ );
+ update_user_meta( $customer->get_id(), '_order_count', $count );
+ }
+
+ return absint( $count );
+ }
+
+ /**
+ * Return how much money this customer has spent.
+ *
+ * @since 3.0.0
+ * @param WC_Customer $customer Customer object.
+ * @return float
+ */
+ public function get_total_spent( &$customer ) {
+ $spent = apply_filters(
+ 'woocommerce_customer_get_total_spent',
+ get_user_meta( $customer->get_id(), '_money_spent', true ),
+ $customer
+ );
+
+ if ( '' === $spent ) {
+ global $wpdb;
+
+ $statuses = array_map( 'esc_sql', wc_get_is_paid_statuses() );
+ $spent = $wpdb->get_var(
+ // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
+ apply_filters(
+ 'woocommerce_customer_get_total_spent_query',
+ "SELECT SUM(meta2.meta_value)
+ FROM $wpdb->posts as posts
+ LEFT JOIN {$wpdb->postmeta} AS meta ON posts.ID = meta.post_id
+ LEFT JOIN {$wpdb->postmeta} AS meta2 ON posts.ID = meta2.post_id
+ WHERE meta.meta_key = '_customer_user'
+ AND meta.meta_value = '" . esc_sql( $customer->get_id() ) . "'
+ AND posts.post_type = 'shop_order'
+ AND posts.post_status IN ( 'wc-" . implode( "','wc-", $statuses ) . "' )
+ AND meta2.meta_key = '_order_total'",
+ $customer
+ )
+ // phpcs:enable
+ );
+
+ if ( ! $spent ) {
+ $spent = 0;
+ }
+ update_user_meta( $customer->get_id(), '_money_spent', $spent );
+ }
+
+ return wc_format_decimal( $spent, 2 );
+ }
+
+ /**
+ * Search customers and return customer IDs.
+ *
+ * @param string $term Search term.
+ * @param int|string $limit Limit search results.
+ * @since 3.0.7
+ *
+ * @return array
+ */
+ public function search_customers( $term, $limit = '' ) {
+ $results = apply_filters( 'woocommerce_customer_pre_search_customers', false, $term, $limit );
+ if ( is_array( $results ) ) {
+ return $results;
+ }
+
+ $query = new WP_User_Query(
+ apply_filters(
+ 'woocommerce_customer_search_customers',
+ array(
+ 'search' => '*' . esc_attr( $term ) . '*',
+ 'search_columns' => array( 'user_login', 'user_url', 'user_email', 'user_nicename', 'display_name' ),
+ 'fields' => 'ID',
+ 'number' => $limit,
+ ),
+ $term,
+ $limit,
+ 'main_query'
+ )
+ );
+
+ $query2 = new WP_User_Query(
+ apply_filters(
+ 'woocommerce_customer_search_customers',
+ array(
+ 'fields' => 'ID',
+ 'number' => $limit,
+ 'meta_query' => array(
+ 'relation' => 'OR',
+ array(
+ 'key' => 'first_name',
+ 'value' => $term,
+ 'compare' => 'LIKE',
+ ),
+ array(
+ 'key' => 'last_name',
+ 'value' => $term,
+ 'compare' => 'LIKE',
+ ),
+ ),
+ ),
+ $term,
+ $limit,
+ 'meta_query'
+ )
+ );
+
+ $results = wp_parse_id_list( array_merge( (array) $query->get_results(), (array) $query2->get_results() ) );
+
+ if ( $limit && count( $results ) > $limit ) {
+ $results = array_slice( $results, 0, $limit );
+ }
+
+ return $results;
+ }
+
+ /**
+ * Get all user ids who have `billing_email` set to any of the email passed in array.
+ *
+ * @param array $emails List of emails to check against.
+ *
+ * @return array
+ */
+ public function get_user_ids_for_billing_email( $emails ) {
+ $emails = array_unique( array_map( 'strtolower', array_map( 'sanitize_email', $emails ) ) );
+ $users_query = new WP_User_Query(
+ array(
+ 'fields' => 'ID',
+ 'meta_query' => array(
+ array(
+ 'key' => 'billing_email',
+ 'value' => $emails,
+ 'compare' => 'IN',
+ ),
+ ),
+ )
+ );
+ return array_unique( $users_query->get_results() );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-customer-download-data-store.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-customer-download-data-store.php
new file mode 100644
index 0000000..379e5fa
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-customer-download-data-store.php
@@ -0,0 +1,447 @@
+get_access_granted( 'edit' ) ) ) {
+ $download->set_access_granted( time() );
+ }
+
+ $data = array(
+ 'download_id' => $download->get_download_id( 'edit' ),
+ 'product_id' => $download->get_product_id( 'edit' ),
+ 'user_id' => $download->get_user_id( 'edit' ),
+ 'user_email' => $download->get_user_email( 'edit' ),
+ 'order_id' => $download->get_order_id( 'edit' ),
+ 'order_key' => $download->get_order_key( 'edit' ),
+ 'downloads_remaining' => $download->get_downloads_remaining( 'edit' ),
+ 'access_granted' => date( 'Y-m-d', $download->get_access_granted( 'edit' )->getTimestamp() ),
+ 'download_count' => $download->get_download_count( 'edit' ),
+ 'access_expires' => ! is_null( $download->get_access_expires( 'edit' ) ) ? date( 'Y-m-d', $download->get_access_expires( 'edit' )->getTimestamp() ) : null,
+ );
+
+ $format = array(
+ '%s',
+ '%s',
+ '%s',
+ '%s',
+ '%s',
+ '%s',
+ '%s',
+ '%s',
+ '%d',
+ '%s',
+ );
+
+ $result = $wpdb->insert(
+ $wpdb->prefix . 'woocommerce_downloadable_product_permissions',
+ apply_filters( 'woocommerce_downloadable_file_permission_data', $data ),
+ apply_filters( 'woocommerce_downloadable_file_permission_format', $format, $data )
+ );
+
+ if ( $result ) {
+ $download->set_id( $wpdb->insert_id );
+ $download->apply_changes();
+ }
+
+ do_action( 'woocommerce_grant_product_download_access', $data );
+ }
+
+ /**
+ * Method to read a download permission from the database.
+ *
+ * @param WC_Customer_Download $download WC_Customer_Download object.
+ *
+ * @throws Exception Throw exception if invalid download is passed.
+ */
+ public function read( &$download ) {
+ global $wpdb;
+
+ if ( ! $download->get_id() ) {
+ throw new Exception( __( 'Invalid download.', 'woocommerce' ) );
+ }
+
+ $download->set_defaults();
+ $raw_download = $wpdb->get_row(
+ $wpdb->prepare(
+ "SELECT * FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE permission_id = %d",
+ $download->get_id()
+ )
+ );
+
+ if ( ! $raw_download ) {
+ throw new Exception( __( 'Invalid download.', 'woocommerce' ) );
+ }
+
+ $download->set_props(
+ array(
+ 'download_id' => $raw_download->download_id,
+ 'product_id' => $raw_download->product_id,
+ 'user_id' => $raw_download->user_id,
+ 'user_email' => $raw_download->user_email,
+ 'order_id' => $raw_download->order_id,
+ 'order_key' => $raw_download->order_key,
+ 'downloads_remaining' => $raw_download->downloads_remaining,
+ 'access_granted' => strtotime( $raw_download->access_granted ),
+ 'download_count' => $raw_download->download_count,
+ 'access_expires' => is_null( $raw_download->access_expires ) ? null : strtotime( $raw_download->access_expires ),
+ )
+ );
+ $download->set_object_read( true );
+ }
+
+ /**
+ * Method to update a download in the database.
+ *
+ * @param WC_Customer_Download $download WC_Customer_Download object.
+ */
+ public function update( &$download ) {
+ global $wpdb;
+
+ $data = array(
+ 'download_id' => $download->get_download_id( 'edit' ),
+ 'product_id' => $download->get_product_id( 'edit' ),
+ 'user_id' => $download->get_user_id( 'edit' ),
+ 'user_email' => $download->get_user_email( 'edit' ),
+ 'order_id' => $download->get_order_id( 'edit' ),
+ 'order_key' => $download->get_order_key( 'edit' ),
+ 'downloads_remaining' => $download->get_downloads_remaining( 'edit' ),
+ 'access_granted' => date( 'Y-m-d', $download->get_access_granted( 'edit' )->getTimestamp() ),
+ 'download_count' => $download->get_download_count( 'edit' ),
+ 'access_expires' => ! is_null( $download->get_access_expires( 'edit' ) ) ? date( 'Y-m-d', $download->get_access_expires( 'edit' )->getTimestamp() ) : null,
+ );
+
+ $format = array(
+ '%s',
+ '%s',
+ '%s',
+ '%s',
+ '%s',
+ '%s',
+ '%s',
+ '%s',
+ '%d',
+ '%s',
+ );
+
+ $wpdb->update(
+ $wpdb->prefix . 'woocommerce_downloadable_product_permissions',
+ $data,
+ array(
+ 'permission_id' => $download->get_id(),
+ ),
+ $format
+ );
+ $download->apply_changes();
+ }
+
+ /**
+ * Method to delete a download permission from the database.
+ *
+ * @param WC_Customer_Download $download WC_Customer_Download object.
+ * @param array $args Array of args to pass to the delete method.
+ */
+ public function delete( &$download, $args = array() ) {
+ global $wpdb;
+
+ $wpdb->query(
+ $wpdb->prepare(
+ "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
+ WHERE permission_id = %d",
+ $download->get_id()
+ )
+ );
+
+ $download->set_id( 0 );
+ }
+
+ /**
+ * Method to delete a download permission from the database by ID.
+ *
+ * @param int $id permission_id of the download to be deleted.
+ */
+ public function delete_by_id( $id ) {
+ global $wpdb;
+ $wpdb->query(
+ $wpdb->prepare(
+ "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
+ WHERE permission_id = %d",
+ $id
+ )
+ );
+ }
+
+ /**
+ * Method to delete a download permission from the database by order ID.
+ *
+ * @param int $id Order ID of the downloads that will be deleted.
+ */
+ public function delete_by_order_id( $id ) {
+ global $wpdb;
+ $wpdb->query(
+ $wpdb->prepare(
+ "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
+ WHERE order_id = %d",
+ $id
+ )
+ );
+ }
+
+ /**
+ * Method to delete a download permission from the database by download ID.
+ *
+ * @param int $id download_id of the downloads that will be deleted.
+ */
+ public function delete_by_download_id( $id ) {
+ global $wpdb;
+ $wpdb->query(
+ $wpdb->prepare(
+ "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
+ WHERE download_id = %s",
+ $id
+ )
+ );
+ }
+
+ /**
+ * Method to delete a download permission from the database by user ID.
+ *
+ * @since 3.4.0
+ * @param int $id user ID of the downloads that will be deleted.
+ * @return bool True if deleted rows.
+ */
+ public function delete_by_user_id( $id ) {
+ global $wpdb;
+ return (bool) $wpdb->query(
+ $wpdb->prepare(
+ "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
+ WHERE user_id = %d",
+ $id
+ )
+ );
+ }
+
+ /**
+ * Method to delete a download permission from the database by user email.
+ *
+ * @since 3.4.0
+ * @param string $email email of the downloads that will be deleted.
+ * @return bool True if deleted rows.
+ */
+ public function delete_by_user_email( $email ) {
+ global $wpdb;
+ return (bool) $wpdb->query(
+ $wpdb->prepare(
+ "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions
+ WHERE user_email = %s",
+ $email
+ )
+ );
+ }
+
+ /**
+ * Get a download object.
+ *
+ * @param array $data From the DB.
+ * @return WC_Customer_Download
+ */
+ private function get_download( $data ) {
+ return new WC_Customer_Download( $data );
+ }
+
+ /**
+ * Get array of download ids by specified args.
+ *
+ * @param array $args Arguments to filter downloads. $args['return'] accepts the following values: 'objects' (default), 'ids' or a comma separeted list of fields (for example: 'order_id,user_id,user_email').
+ * @return array Can be an array of permission_ids, an array of WC_Customer_Download objects or an array of arrays containing specified fields depending on the value of $args['return'].
+ */
+ public function get_downloads( $args = array() ) {
+ global $wpdb;
+
+ $args = wp_parse_args(
+ $args,
+ array(
+ 'user_email' => '',
+ 'user_id' => '',
+ 'order_id' => '',
+ 'order_key' => '',
+ 'product_id' => '',
+ 'download_id' => '',
+ 'orderby' => 'permission_id',
+ 'order' => 'ASC',
+ 'limit' => -1,
+ 'page' => 1,
+ 'return' => 'objects',
+ )
+ );
+
+ $valid_fields = array( 'permission_id', 'download_id', 'product_id', 'order_id', 'order_key', 'user_email', 'user_id', 'downloads_remaining', 'access_granted', 'access_expires', 'download_count' );
+ $get_results_output = ARRAY_A;
+
+ if ( 'ids' === $args['return'] ) {
+ $fields = 'permission_id';
+ } elseif ( 'objects' === $args['return'] ) {
+ $fields = '*';
+ $get_results_output = OBJECT;
+ } else {
+ $fields = explode( ',', (string) $args['return'] );
+ $fields = implode( ', ', array_intersect( $fields, $valid_fields ) );
+ }
+
+ $query = array();
+ $query[] = "SELECT {$fields} FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE 1=1";
+
+ if ( $args['user_email'] ) {
+ $query[] = $wpdb->prepare( 'AND user_email = %s', sanitize_email( $args['user_email'] ) );
+ }
+
+ if ( $args['user_id'] ) {
+ $query[] = $wpdb->prepare( 'AND user_id = %d', absint( $args['user_id'] ) );
+ }
+
+ if ( $args['order_id'] ) {
+ $query[] = $wpdb->prepare( 'AND order_id = %d', $args['order_id'] );
+ }
+
+ if ( $args['order_key'] ) {
+ $query[] = $wpdb->prepare( 'AND order_key = %s', $args['order_key'] );
+ }
+
+ if ( $args['product_id'] ) {
+ $query[] = $wpdb->prepare( 'AND product_id = %d', $args['product_id'] );
+ }
+
+ if ( $args['download_id'] ) {
+ $query[] = $wpdb->prepare( 'AND download_id = %s', $args['download_id'] );
+ }
+
+ $orderby = in_array( $args['orderby'], $valid_fields, true ) ? $args['orderby'] : 'permission_id';
+ $order = 'DESC' === strtoupper( $args['order'] ) ? 'DESC' : 'ASC';
+ $orderby_sql = sanitize_sql_orderby( "{$orderby} {$order}" );
+ $query[] = "ORDER BY {$orderby_sql}";
+
+ if ( 0 < $args['limit'] ) {
+ $query[] = $wpdb->prepare( 'LIMIT %d, %d', absint( $args['limit'] ) * absint( $args['page'] - 1 ), absint( $args['limit'] ) );
+ }
+
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
+ $results = $wpdb->get_results( implode( ' ', $query ), $get_results_output );
+
+ switch ( $args['return'] ) {
+ case 'ids':
+ return wp_list_pluck( $results, 'permission_id' );
+ case 'objects':
+ return array_map( array( $this, 'get_download' ), $results );
+ default:
+ return $results;
+ }
+ }
+
+ /**
+ * Update download ids if the hash changes.
+ *
+ * @deprecated 3.3.0 Download id is now a static UUID and should not be changed based on file hash.
+ *
+ * @param int $product_id Product ID.
+ * @param string $old_id Old download_id.
+ * @param string $new_id New download_id.
+ */
+ public function update_download_id( $product_id, $old_id, $new_id ) {
+ global $wpdb;
+
+ wc_deprecated_function( __METHOD__, '3.3' );
+
+ $wpdb->update(
+ $wpdb->prefix . 'woocommerce_downloadable_product_permissions',
+ array(
+ 'download_id' => $new_id,
+ ),
+ array(
+ 'download_id' => $old_id,
+ 'product_id' => $product_id,
+ )
+ );
+ }
+
+ /**
+ * Get a customers downloads.
+ *
+ * @param int $customer_id Customer ID.
+ * @return array
+ */
+ public function get_downloads_for_customer( $customer_id ) {
+ global $wpdb;
+
+ return $wpdb->get_results(
+ $wpdb->prepare(
+ "SELECT * FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions as permissions
+ WHERE user_id = %d
+ AND permissions.order_id > 0
+ AND
+ (
+ permissions.downloads_remaining > 0
+ OR permissions.downloads_remaining = ''
+ )
+ AND
+ (
+ permissions.access_expires IS NULL
+ OR permissions.access_expires >= %s
+ OR permissions.access_expires = '0000-00-00 00:00:00'
+ )
+ ORDER BY permissions.order_id, permissions.product_id, permissions.permission_id;",
+ $customer_id,
+ date( 'Y-m-d', current_time( 'timestamp' ) )
+ )
+ );
+ }
+
+ /**
+ * Update user prop for downloads based on order id.
+ *
+ * @param int $order_id Order ID.
+ * @param int $customer_id Customer ID.
+ * @param string $email Customer email address.
+ */
+ public function update_user_by_order_id( $order_id, $customer_id, $email ) {
+ global $wpdb;
+ $wpdb->update(
+ $wpdb->prefix . 'woocommerce_downloadable_product_permissions',
+ array(
+ 'user_id' => $customer_id,
+ 'user_email' => $email,
+ ),
+ array(
+ 'order_id' => $order_id,
+ ),
+ array(
+ '%d',
+ '%s',
+ ),
+ array(
+ '%d',
+ )
+ );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-customer-download-log-data-store.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-customer-download-log-data-store.php
new file mode 100644
index 0000000..12b59a5
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-customer-download-log-data-store.php
@@ -0,0 +1,239 @@
+get_timestamp( 'edit' ) ) ) {
+ $download_log->set_timestamp( time() );
+ }
+
+ $data = array(
+ 'timestamp' => date( 'Y-m-d H:i:s', $download_log->get_timestamp( 'edit' )->getTimestamp() ),
+ 'permission_id' => $download_log->get_permission_id( 'edit' ),
+ 'user_id' => $download_log->get_user_id( 'edit' ),
+ 'user_ip_address' => $download_log->get_user_ip_address( 'edit' ),
+ );
+
+ $format = array(
+ '%s',
+ '%s',
+ '%s',
+ '%s',
+ );
+
+ $result = $wpdb->insert(
+ $wpdb->prefix . self::get_table_name(),
+ apply_filters( 'woocommerce_downloadable_product_download_log_insert_data', $data ),
+ apply_filters( 'woocommerce_downloadable_product_download_log_insert_format', $format, $data )
+ );
+
+ do_action( 'woocommerce_downloadable_product_download_log_insert', $data );
+
+ if ( $result ) {
+ $download_log->set_id( $wpdb->insert_id );
+ $download_log->apply_changes();
+ } else {
+ wp_die( esc_html__( 'Unable to insert download log entry in database.', 'woocommerce' ) );
+ }
+ }
+
+ /**
+ * Method to read a download log from the database.
+ *
+ * @param WC_Customer_Download_Log $download_log Download log object.
+ * @throws Exception Exception when read is not possible.
+ */
+ public function read( &$download_log ) {
+ global $wpdb;
+
+ $download_log->set_defaults();
+
+ // Ensure we have an id to pull from the DB.
+ if ( ! $download_log->get_id() ) {
+ throw new Exception( __( 'Invalid download log: no ID.', 'woocommerce' ) );
+ }
+
+ $table = $wpdb->prefix . self::get_table_name();
+
+ // Query the DB for the download log.
+ $raw_download_log = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$table} WHERE download_log_id = %d", $download_log->get_id() ) ); // WPCS: unprepared SQL ok.
+
+ if ( ! $raw_download_log ) {
+ throw new Exception( __( 'Invalid download log: not found.', 'woocommerce' ) );
+ }
+
+ $download_log->set_props(
+ array(
+ 'timestamp' => strtotime( $raw_download_log->timestamp ),
+ 'permission_id' => $raw_download_log->permission_id,
+ 'user_id' => $raw_download_log->user_id,
+ 'user_ip_address' => $raw_download_log->user_ip_address,
+ )
+ );
+
+ $download_log->set_object_read( true );
+ }
+
+ /**
+ * Method to update a download log in the database.
+ *
+ * @param WC_Customer_Download_Log $download_log Download log object.
+ */
+ public function update( &$download_log ) {
+ global $wpdb;
+
+ $data = array(
+ 'timestamp' => date( 'Y-m-d H:i:s', $download_log->get_timestamp( 'edit' )->getTimestamp() ),
+ 'permission_id' => $download_log->get_permission_id( 'edit' ),
+ 'user_id' => $download_log->get_user_id( 'edit' ),
+ 'user_ip_address' => $download_log->get_user_ip_address( 'edit' ),
+ );
+
+ $format = array(
+ '%s',
+ '%s',
+ '%s',
+ '%s',
+ );
+
+ $wpdb->update(
+ $wpdb->prefix . self::get_table_name(),
+ $data,
+ array(
+ 'download_log_id' => $download_log->get_id(),
+ ),
+ $format
+ );
+ $download_log->apply_changes();
+ }
+
+ /**
+ * Get a download log object.
+ *
+ * @param array $data From the DB.
+ * @return WC_Customer_Download_Log
+ */
+ private function get_download_log( $data ) {
+ return new WC_Customer_Download_Log( $data );
+ }
+
+ /**
+ * Get array of download log ids by specified args.
+ *
+ * @param array $args Arguments to define download logs to retrieve.
+ * @return array
+ */
+ public function get_download_logs( $args = array() ) {
+ global $wpdb;
+
+ $args = wp_parse_args(
+ $args,
+ array(
+ 'permission_id' => '',
+ 'user_id' => '',
+ 'user_ip_address' => '',
+ 'orderby' => 'download_log_id',
+ 'order' => 'ASC',
+ 'limit' => -1,
+ 'page' => 1,
+ 'return' => 'objects',
+ )
+ );
+
+ $query = array();
+ $table = $wpdb->prefix . self::get_table_name();
+ $query[] = "SELECT * FROM {$table} WHERE 1=1";
+
+ if ( $args['permission_id'] ) {
+ $query[] = $wpdb->prepare( 'AND permission_id = %d', $args['permission_id'] );
+ }
+
+ if ( $args['user_id'] ) {
+ $query[] = $wpdb->prepare( 'AND user_id = %d', $args['user_id'] );
+ }
+
+ if ( $args['user_ip_address'] ) {
+ $query[] = $wpdb->prepare( 'AND user_ip_address = %s', $args['user_ip_address'] );
+ }
+
+ $allowed_orders = array( 'download_log_id', 'timestamp', 'permission_id', 'user_id' );
+ $orderby = in_array( $args['orderby'], $allowed_orders, true ) ? $args['orderby'] : 'download_log_id';
+ $order = 'DESC' === strtoupper( $args['order'] ) ? 'DESC' : 'ASC';
+ $orderby_sql = sanitize_sql_orderby( "{$orderby} {$order}" );
+ $query[] = "ORDER BY {$orderby_sql}";
+
+ if ( 0 < $args['limit'] ) {
+ $query[] = $wpdb->prepare( 'LIMIT %d, %d', absint( $args['limit'] ) * absint( $args['page'] - 1 ), absint( $args['limit'] ) );
+ }
+
+ $raw_download_logs = $wpdb->get_results( implode( ' ', $query ) ); // WPCS: unprepared SQL ok.
+
+ switch ( $args['return'] ) {
+ case 'ids':
+ return wp_list_pluck( $raw_download_logs, 'download_log_id' );
+ default:
+ return array_map( array( $this, 'get_download_log' ), $raw_download_logs );
+ }
+ }
+
+ /**
+ * Get download logs for a given download permission.
+ *
+ * @param int $permission_id Permission to get logs for.
+ * @return array
+ */
+ public function get_download_logs_for_permission( $permission_id ) {
+ // If no permission_id is passed, return an empty array.
+ if ( empty( $permission_id ) ) {
+ return array();
+ }
+
+ return $this->get_download_logs(
+ array(
+ 'permission_id' => $permission_id,
+ )
+ );
+ }
+
+ /**
+ * Method to delete download logs for a given permission ID.
+ *
+ * @since 3.4.0
+ * @param int $id download_id of the downloads that will be deleted.
+ */
+ public function delete_by_permission_id( $id ) {
+ global $wpdb;
+ $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE permission_id = %d", $id ) );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-data-store-wp.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-data-store-wp.php
new file mode 100644
index 0000000..d8b5edf
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-data-store-wp.php
@@ -0,0 +1,645 @@
+get_id();
+ }
+ $terms = get_the_terms( $object_id, $taxonomy );
+ if ( false === $terms || is_wp_error( $terms ) ) {
+ return array();
+ }
+ return wp_list_pluck( $terms, 'term_id' );
+ }
+
+ /**
+ * Returns an array of meta for an object.
+ *
+ * @since 3.0.0
+ * @param WC_Data $object WC_Data object.
+ * @return array
+ */
+ public function read_meta( &$object ) {
+ global $wpdb;
+ $db_info = $this->get_db_info();
+ $raw_meta_data = $wpdb->get_results(
+ $wpdb->prepare(
+ // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
+ "SELECT {$db_info['meta_id_field']} as meta_id, meta_key, meta_value
+ FROM {$db_info['table']}
+ WHERE {$db_info['object_id_field']} = %d
+ ORDER BY {$db_info['meta_id_field']}",
+ // phpcs:enable
+ $object->get_id()
+ )
+ );
+
+ $this->internal_meta_keys = array_merge( array_map( array( $this, 'prefix_key' ), $object->get_data_keys() ), $this->internal_meta_keys );
+ $meta_data = array_filter( $raw_meta_data, array( $this, 'exclude_internal_meta_keys' ) );
+ return apply_filters( "woocommerce_data_store_wp_{$this->meta_type}_read_meta", $meta_data, $object, $this );
+ }
+
+ /**
+ * Deletes meta based on meta ID.
+ *
+ * @since 3.0.0
+ * @param WC_Data $object WC_Data object.
+ * @param stdClass $meta (containing at least ->id).
+ */
+ public function delete_meta( &$object, $meta ) {
+ delete_metadata_by_mid( $this->meta_type, $meta->id );
+ }
+
+ /**
+ * Add new piece of meta.
+ *
+ * @since 3.0.0
+ * @param WC_Data $object WC_Data object.
+ * @param stdClass $meta (containing ->key and ->value).
+ * @return int meta ID
+ */
+ public function add_meta( &$object, $meta ) {
+ return add_metadata( $this->meta_type, $object->get_id(), wp_slash( $meta->key ), is_string( $meta->value ) ? wp_slash( $meta->value ) : $meta->value, false );
+ }
+
+ /**
+ * Update meta.
+ *
+ * @since 3.0.0
+ * @param WC_Data $object WC_Data object.
+ * @param stdClass $meta (containing ->id, ->key and ->value).
+ */
+ public function update_meta( &$object, $meta ) {
+ update_metadata_by_mid( $this->meta_type, $meta->id, $meta->value, $meta->key );
+ }
+
+ /**
+ * Table structure is slightly different between meta types, this function will return what we need to know.
+ *
+ * @since 3.0.0
+ * @return array Array elements: table, object_id_field, meta_id_field
+ */
+ protected function get_db_info() {
+ global $wpdb;
+
+ $meta_id_field = 'meta_id'; // for some reason users calls this umeta_id so we need to track this as well.
+ $table = $wpdb->prefix;
+
+ // If we are dealing with a type of metadata that is not a core type, the table should be prefixed.
+ if ( ! in_array( $this->meta_type, array( 'post', 'user', 'comment', 'term' ), true ) ) {
+ $table .= 'woocommerce_';
+ }
+
+ $table .= $this->meta_type . 'meta';
+ $object_id_field = $this->meta_type . '_id';
+
+ // Figure out our field names.
+ if ( 'user' === $this->meta_type ) {
+ $meta_id_field = 'umeta_id';
+ $table = $wpdb->usermeta;
+ }
+
+ if ( ! empty( $this->object_id_field_for_meta ) ) {
+ $object_id_field = $this->object_id_field_for_meta;
+ }
+
+ return array(
+ 'table' => $table,
+ 'object_id_field' => $object_id_field,
+ 'meta_id_field' => $meta_id_field,
+ );
+ }
+
+ /**
+ * Internal meta keys we don't want exposed as part of meta_data. This is in
+ * addition to all data props with _ prefix.
+ *
+ * @since 2.6.0
+ *
+ * @param string $key Prefix to be added to meta keys.
+ * @return string
+ */
+ protected function prefix_key( $key ) {
+ return '_' === substr( $key, 0, 1 ) ? $key : '_' . $key;
+ }
+
+ /**
+ * Callback to remove unwanted meta data.
+ *
+ * @param object $meta Meta object to check if it should be excluded or not.
+ * @return bool
+ */
+ protected function exclude_internal_meta_keys( $meta ) {
+ return ! in_array( $meta->meta_key, $this->internal_meta_keys, true ) && 0 !== stripos( $meta->meta_key, 'wp_' );
+ }
+
+ /**
+ * Gets a list of props and meta keys that need updated based on change state
+ * or if they are present in the database or not.
+ *
+ * @param WC_Data $object The WP_Data object (WC_Coupon for coupons, etc).
+ * @param array $meta_key_to_props A mapping of meta keys => prop names.
+ * @param string $meta_type The internal WP meta type (post, user, etc).
+ * @return array A mapping of meta keys => prop names, filtered by ones that should be updated.
+ */
+ protected function get_props_to_update( $object, $meta_key_to_props, $meta_type = 'post' ) {
+ $props_to_update = array();
+ $changed_props = $object->get_changes();
+
+ // Props should be updated if they are a part of the $changed array or don't exist yet.
+ foreach ( $meta_key_to_props as $meta_key => $prop ) {
+ if ( array_key_exists( $prop, $changed_props ) || ! metadata_exists( $meta_type, $object->get_id(), $meta_key ) ) {
+ $props_to_update[ $meta_key ] = $prop;
+ }
+ }
+
+ return $props_to_update;
+ }
+
+ /**
+ * Update meta data in, or delete it from, the database.
+ *
+ * Avoids storing meta when it's either an empty string or empty array.
+ * Other empty values such as numeric 0 and null should still be stored.
+ * Data-stores can force meta to exist using `must_exist_meta_keys`.
+ *
+ * Note: WordPress `get_metadata` function returns an empty string when meta data does not exist.
+ *
+ * @param WC_Data $object The WP_Data object (WC_Coupon for coupons, etc).
+ * @param string $meta_key Meta key to update.
+ * @param mixed $meta_value Value to save.
+ *
+ * @since 3.6.0 Added to prevent empty meta being stored unless required.
+ *
+ * @return bool True if updated/deleted.
+ */
+ protected function update_or_delete_post_meta( $object, $meta_key, $meta_value ) {
+ if ( in_array( $meta_value, array( array(), '' ), true ) && ! in_array( $meta_key, $this->must_exist_meta_keys, true ) ) {
+ $updated = delete_post_meta( $object->get_id(), $meta_key );
+ } else {
+ $updated = update_post_meta( $object->get_id(), $meta_key, $meta_value );
+ }
+
+ return (bool) $updated;
+ }
+
+ /**
+ * Get valid WP_Query args from a WC_Object_Query's query variables.
+ *
+ * @since 3.1.0
+ * @param array $query_vars query vars from a WC_Object_Query.
+ * @return array
+ */
+ protected function get_wp_query_args( $query_vars ) {
+
+ $skipped_values = array( '', array(), null );
+ $wp_query_args = array(
+ 'errors' => array(),
+ 'meta_query' => array(), // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
+ );
+
+ foreach ( $query_vars as $key => $value ) {
+ if ( in_array( $value, $skipped_values, true ) || 'meta_query' === $key ) {
+ continue;
+ }
+
+ // Build meta queries out of vars that are stored in internal meta keys.
+ if ( in_array( '_' . $key, $this->internal_meta_keys, true ) ) {
+ // Check for existing values if wildcard is used.
+ if ( '*' === $value ) {
+ $wp_query_args['meta_query'][] = array(
+ array(
+ 'key' => '_' . $key,
+ 'compare' => 'EXISTS',
+ ),
+ array(
+ 'key' => '_' . $key,
+ 'value' => '',
+ 'compare' => '!=',
+ ),
+ );
+ } else {
+ $wp_query_args['meta_query'][] = array(
+ 'key' => '_' . $key,
+ 'value' => $value,
+ 'compare' => is_array( $value ) ? 'IN' : '=',
+ );
+ }
+ } else { // Other vars get mapped to wp_query args or just left alone.
+ $key_mapping = array(
+ 'parent' => 'post_parent',
+ 'parent_exclude' => 'post_parent__not_in',
+ 'exclude' => 'post__not_in',
+ 'limit' => 'posts_per_page',
+ 'type' => 'post_type',
+ 'return' => 'fields',
+ );
+
+ if ( isset( $key_mapping[ $key ] ) ) {
+ $wp_query_args[ $key_mapping[ $key ] ] = $value;
+ } else {
+ $wp_query_args[ $key ] = $value;
+ }
+ }
+ }
+
+ return apply_filters( 'woocommerce_get_wp_query_args', $wp_query_args, $query_vars );
+ }
+
+ /**
+ * Map a valid date query var to WP_Query arguments.
+ * Valid date formats: YYYY-MM-DD or timestamp, possibly combined with an operator from $valid_operators.
+ * Also accepts a WC_DateTime object.
+ *
+ * @since 3.2.0
+ * @param mixed $query_var A valid date format.
+ * @param string $key meta or db column key.
+ * @param array $wp_query_args WP_Query args.
+ * @return array Modified $wp_query_args
+ */
+ public function parse_date_for_wp_query( $query_var, $key, $wp_query_args = array() ) {
+ $query_parse_regex = '/([^.<>]*)(>=|<=|>|<|\.\.\.)([^.<>]+)/';
+ $valid_operators = array( '>', '>=', '=', '<=', '<', '...' );
+
+ // YYYY-MM-DD queries have 'day' precision. Timestamp/WC_DateTime queries have 'second' precision.
+ $precision = 'second';
+
+ $dates = array();
+ $operator = '=';
+
+ try {
+ // Specific time query with a WC_DateTime.
+ if ( is_a( $query_var, 'WC_DateTime' ) ) {
+ $dates[] = $query_var;
+ } elseif ( is_numeric( $query_var ) ) { // Specific time query with a timestamp.
+ $dates[] = new WC_DateTime( "@{$query_var}", new DateTimeZone( 'UTC' ) );
+ } elseif ( preg_match( $query_parse_regex, $query_var, $sections ) ) { // Query with operators and possible range of dates.
+ if ( ! empty( $sections[1] ) ) {
+ $dates[] = is_numeric( $sections[1] ) ? new WC_DateTime( "@{$sections[1]}", new DateTimeZone( 'UTC' ) ) : wc_string_to_datetime( $sections[1] );
+ }
+
+ $operator = in_array( $sections[2], $valid_operators, true ) ? $sections[2] : '';
+ $dates[] = is_numeric( $sections[3] ) ? new WC_DateTime( "@{$sections[3]}", new DateTimeZone( 'UTC' ) ) : wc_string_to_datetime( $sections[3] );
+
+ if ( ! is_numeric( $sections[1] ) && ! is_numeric( $sections[3] ) ) {
+ $precision = 'day';
+ }
+ } else { // Specific time query with a string.
+ $dates[] = wc_string_to_datetime( $query_var );
+ $precision = 'day';
+ }
+ } catch ( Exception $e ) {
+ return $wp_query_args;
+ }
+
+ // Check for valid inputs.
+ if ( ! $operator || empty( $dates ) || ( '...' === $operator && count( $dates ) < 2 ) ) {
+ return $wp_query_args;
+ }
+
+ // Build date query for 'post_date' or 'post_modified' keys.
+ if ( 'post_date' === $key || 'post_modified' === $key ) {
+ if ( ! isset( $wp_query_args['date_query'] ) ) {
+ $wp_query_args['date_query'] = array();
+ }
+
+ $query_arg = array(
+ 'column' => 'day' === $precision ? $key : $key . '_gmt',
+ 'inclusive' => '>' !== $operator && '<' !== $operator,
+ );
+
+ // Add 'before'/'after' query args.
+ $comparisons = array();
+ if ( '>' === $operator || '>=' === $operator || '...' === $operator ) {
+ $comparisons[] = 'after';
+ }
+ if ( '<' === $operator || '<=' === $operator || '...' === $operator ) {
+ $comparisons[] = 'before';
+ }
+
+ foreach ( $comparisons as $index => $comparison ) {
+ if ( 'day' === $precision ) {
+ /**
+ * WordPress doesn't generate the correct SQL for inclusive day queries with both a 'before' and
+ * 'after' string query, so we have to use the array format in 'day' precision.
+ *
+ * @see https://core.trac.wordpress.org/ticket/29908
+ */
+ $query_arg[ $comparison ]['year'] = $dates[ $index ]->date( 'Y' );
+ $query_arg[ $comparison ]['month'] = $dates[ $index ]->date( 'n' );
+ $query_arg[ $comparison ]['day'] = $dates[ $index ]->date( 'j' );
+ } else {
+ /**
+ * WordPress doesn't support 'hour'/'second'/'minute' in array format 'before'/'after' queries,
+ * so we have to use a string query.
+ */
+ $query_arg[ $comparison ] = gmdate( 'm/d/Y H:i:s', $dates[ $index ]->getTimestamp() );
+ }
+ }
+
+ if ( empty( $comparisons ) ) {
+ $query_arg['year'] = $dates[0]->date( 'Y' );
+ $query_arg['month'] = $dates[0]->date( 'n' );
+ $query_arg['day'] = $dates[0]->date( 'j' );
+ if ( 'second' === $precision ) {
+ $query_arg['hour'] = $dates[0]->date( 'H' );
+ $query_arg['minute'] = $dates[0]->date( 'i' );
+ $query_arg['second'] = $dates[0]->date( 's' );
+ }
+ }
+ $wp_query_args['date_query'][] = $query_arg;
+ return $wp_query_args;
+ }
+
+ // Build meta query for unrecognized keys.
+ if ( ! isset( $wp_query_args['meta_query'] ) ) {
+ $wp_query_args['meta_query'] = array(); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
+ }
+
+ // Meta dates are stored as timestamps in the db.
+ // Check against beginning/end-of-day timestamps when using 'day' precision.
+ if ( 'day' === $precision ) {
+ $start_timestamp = strtotime( gmdate( 'm/d/Y 00:00:00', $dates[0]->getTimestamp() ) );
+ $end_timestamp = '...' !== $operator ? ( $start_timestamp + DAY_IN_SECONDS ) : strtotime( gmdate( 'm/d/Y 00:00:00', $dates[1]->getTimestamp() ) );
+ switch ( $operator ) {
+ case '>':
+ case '<=':
+ $wp_query_args['meta_query'][] = array(
+ 'key' => $key,
+ 'value' => $end_timestamp,
+ 'compare' => $operator,
+ );
+ break;
+ case '<':
+ case '>=':
+ $wp_query_args['meta_query'][] = array(
+ 'key' => $key,
+ 'value' => $start_timestamp,
+ 'compare' => $operator,
+ );
+ break;
+ default:
+ $wp_query_args['meta_query'][] = array(
+ 'key' => $key,
+ 'value' => $start_timestamp,
+ 'compare' => '>=',
+ );
+ $wp_query_args['meta_query'][] = array(
+ 'key' => $key,
+ 'value' => $end_timestamp,
+ 'compare' => '<=',
+ );
+ }
+ } else {
+ if ( '...' !== $operator ) {
+ $wp_query_args['meta_query'][] = array(
+ 'key' => $key,
+ 'value' => $dates[0]->getTimestamp(),
+ 'compare' => $operator,
+ );
+ } else {
+ $wp_query_args['meta_query'][] = array(
+ 'key' => $key,
+ 'value' => $dates[0]->getTimestamp(),
+ 'compare' => '>=',
+ );
+ $wp_query_args['meta_query'][] = array(
+ 'key' => $key,
+ 'value' => $dates[1]->getTimestamp(),
+ 'compare' => '<=',
+ );
+ }
+ }
+
+ return $wp_query_args;
+ }
+
+ /**
+ * Return list of internal meta keys.
+ *
+ * @since 3.2.0
+ * @return array
+ */
+ public function get_internal_meta_keys() {
+ return $this->internal_meta_keys;
+ }
+
+ /**
+ * Check if the terms are suitable for searching.
+ *
+ * Uses an array of stopwords (terms) that are excluded from the separate
+ * term matching when searching for posts. The list of English stopwords is
+ * the approximate search engines list, and is translatable.
+ *
+ * @since 3.4.0
+ * @param array $terms Terms to check.
+ * @return array Terms that are not stopwords.
+ */
+ protected function get_valid_search_terms( $terms ) {
+ $valid_terms = array();
+ $stopwords = $this->get_search_stopwords();
+
+ foreach ( $terms as $term ) {
+ // keep before/after spaces when term is for exact match, otherwise trim quotes and spaces.
+ if ( preg_match( '/^".+"$/', $term ) ) {
+ $term = trim( $term, "\"'" );
+ } else {
+ $term = trim( $term, "\"' " );
+ }
+
+ // Avoid single A-Z and single dashes.
+ if ( empty( $term ) || ( 1 === strlen( $term ) && preg_match( '/^[a-z\-]$/i', $term ) ) ) {
+ continue;
+ }
+
+ if ( in_array( wc_strtolower( $term ), $stopwords, true ) ) {
+ continue;
+ }
+
+ $valid_terms[] = $term;
+ }
+
+ return $valid_terms;
+ }
+
+ /**
+ * Retrieve stopwords used when parsing search terms.
+ *
+ * @since 3.4.0
+ * @return array Stopwords.
+ */
+ protected function get_search_stopwords() {
+ // Translators: This is a comma-separated list of very common words that should be excluded from a search, like a, an, and the. These are usually called "stopwords". You should not simply translate these individual words into your language. Instead, look for and provide commonly accepted stopwords in your language.
+ $stopwords = array_map(
+ 'wc_strtolower',
+ array_map(
+ 'trim',
+ explode(
+ ',',
+ _x(
+ 'about,an,are,as,at,be,by,com,for,from,how,in,is,it,of,on,or,that,the,this,to,was,what,when,where,who,will,with,www',
+ 'Comma-separated list of search stopwords in your language',
+ 'woocommerce'
+ )
+ )
+ )
+ );
+
+ return apply_filters( 'wp_search_stopwords', $stopwords );
+ }
+
+ /**
+ * Get data to save to a lookup table.
+ *
+ * @since 3.6.0
+ * @param int $id ID of object to update.
+ * @param string $table Lookup table name.
+ * @return array
+ */
+ protected function get_data_for_lookup_table( $id, $table ) {
+ return array();
+ }
+
+ /**
+ * Get primary key name for lookup table.
+ *
+ * @since 3.6.0
+ * @param string $table Lookup table name.
+ * @return string
+ */
+ protected function get_primary_key_for_lookup_table( $table ) {
+ return '';
+ }
+
+ /**
+ * Update a lookup table for an object.
+ *
+ * @since 3.6.0
+ * @param int $id ID of object to update.
+ * @param string $table Lookup table name.
+ *
+ * @return NULL
+ */
+ protected function update_lookup_table( $id, $table ) {
+ global $wpdb;
+
+ $id = absint( $id );
+ $table = sanitize_key( $table );
+
+ if ( empty( $id ) || empty( $table ) ) {
+ return false;
+ }
+
+ $existing_data = wp_cache_get( 'lookup_table', 'object_' . $id );
+ $update_data = $this->get_data_for_lookup_table( $id, $table );
+
+ if ( ! empty( $update_data ) && $update_data !== $existing_data ) {
+ $wpdb->replace(
+ $wpdb->$table,
+ $update_data
+ );
+ wp_cache_set( 'lookup_table', $update_data, 'object_' . $id );
+ }
+ }
+
+ /**
+ * Delete lookup table data for an ID.
+ *
+ * @since 3.6.0
+ * @param int $id ID of object to update.
+ * @param string $table Lookup table name.
+ */
+ public function delete_from_lookup_table( $id, $table ) {
+ global $wpdb;
+
+ $id = absint( $id );
+ $table = sanitize_key( $table );
+
+ if ( empty( $id ) || empty( $table ) ) {
+ return false;
+ }
+
+ $pk = $this->get_primary_key_for_lookup_table( $table );
+
+ $wpdb->delete(
+ $wpdb->$table,
+ array(
+ $pk => $id,
+ )
+ );
+ wp_cache_delete( 'lookup_table', 'object_' . $id );
+ }
+
+ /**
+ * Converts a WP post date string into a timestamp.
+ *
+ * @since 4.8.0
+ *
+ * @param string $time_string The WP post date string.
+ * @return int|null The date string converted to a timestamp or null.
+ */
+ protected function string_to_timestamp( $time_string ) {
+ return '0000-00-00 00:00:00' !== $time_string ? wc_string_to_timestamp( $time_string ) : null;
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-data-store-cpt.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-data-store-cpt.php
new file mode 100644
index 0000000..0e19ecd
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-data-store-cpt.php
@@ -0,0 +1,893 @@
+get_order_key() ) {
+ $order->set_order_key( wc_generate_order_key() );
+ }
+ parent::create( $order );
+ do_action( 'woocommerce_new_order', $order->get_id(), $order );
+ }
+
+ /**
+ * Read order data. Can be overridden by child classes to load other props.
+ *
+ * @param WC_Order $order Order object.
+ * @param object $post_object Post object.
+ * @since 3.0.0
+ */
+ protected function read_order_data( &$order, $post_object ) {
+ parent::read_order_data( $order, $post_object );
+ $id = $order->get_id();
+ $date_completed = get_post_meta( $id, '_date_completed', true );
+ $date_paid = get_post_meta( $id, '_date_paid', true );
+
+ if ( ! $date_completed ) {
+ $date_completed = get_post_meta( $id, '_completed_date', true );
+ }
+
+ if ( ! $date_paid ) {
+ $date_paid = get_post_meta( $id, '_paid_date', true );
+ }
+
+ $order->set_props(
+ array(
+ 'order_key' => get_post_meta( $id, '_order_key', true ),
+ 'customer_id' => get_post_meta( $id, '_customer_user', true ),
+ 'billing_first_name' => get_post_meta( $id, '_billing_first_name', true ),
+ 'billing_last_name' => get_post_meta( $id, '_billing_last_name', true ),
+ 'billing_company' => get_post_meta( $id, '_billing_company', true ),
+ 'billing_address_1' => get_post_meta( $id, '_billing_address_1', true ),
+ 'billing_address_2' => get_post_meta( $id, '_billing_address_2', true ),
+ 'billing_city' => get_post_meta( $id, '_billing_city', true ),
+ 'billing_state' => get_post_meta( $id, '_billing_state', true ),
+ 'billing_postcode' => get_post_meta( $id, '_billing_postcode', true ),
+ 'billing_country' => get_post_meta( $id, '_billing_country', true ),
+ 'billing_email' => get_post_meta( $id, '_billing_email', true ),
+ 'billing_phone' => get_post_meta( $id, '_billing_phone', true ),
+ 'shipping_first_name' => get_post_meta( $id, '_shipping_first_name', true ),
+ 'shipping_last_name' => get_post_meta( $id, '_shipping_last_name', true ),
+ 'shipping_company' => get_post_meta( $id, '_shipping_company', true ),
+ 'shipping_address_1' => get_post_meta( $id, '_shipping_address_1', true ),
+ 'shipping_address_2' => get_post_meta( $id, '_shipping_address_2', true ),
+ 'shipping_city' => get_post_meta( $id, '_shipping_city', true ),
+ 'shipping_state' => get_post_meta( $id, '_shipping_state', true ),
+ 'shipping_postcode' => get_post_meta( $id, '_shipping_postcode', true ),
+ 'shipping_country' => get_post_meta( $id, '_shipping_country', true ),
+ 'payment_method' => get_post_meta( $id, '_payment_method', true ),
+ 'payment_method_title' => get_post_meta( $id, '_payment_method_title', true ),
+ 'transaction_id' => get_post_meta( $id, '_transaction_id', true ),
+ 'customer_ip_address' => get_post_meta( $id, '_customer_ip_address', true ),
+ 'customer_user_agent' => get_post_meta( $id, '_customer_user_agent', true ),
+ 'created_via' => get_post_meta( $id, '_created_via', true ),
+ 'date_completed' => $date_completed,
+ 'date_paid' => $date_paid,
+ 'cart_hash' => get_post_meta( $id, '_cart_hash', true ),
+ 'customer_note' => $post_object->post_excerpt,
+ )
+ );
+ }
+
+ /**
+ * Method to update an order in the database.
+ *
+ * @param WC_Order $order Order object.
+ */
+ public function update( &$order ) {
+ // Before updating, ensure date paid is set if missing.
+ if ( ! $order->get_date_paid( 'edit' ) && version_compare( $order->get_version( 'edit' ), '3.0', '<' ) && $order->has_status( apply_filters( 'woocommerce_payment_complete_order_status', $order->needs_processing() ? 'processing' : 'completed', $order->get_id(), $order ) ) ) {
+ $order->set_date_paid( $order->get_date_created( 'edit' ) );
+ }
+
+ // Also grab the current status so we can compare.
+ $previous_status = get_post_status( $order->get_id() );
+
+ // Update the order.
+ parent::update( $order );
+
+ // Fire a hook depending on the status - this should be considered a creation if it was previously draft status.
+ $new_status = $order->get_status( 'edit' );
+
+ if ( $new_status !== $previous_status && in_array( $previous_status, array( 'new', 'auto-draft', 'draft' ), true ) ) {
+ do_action( 'woocommerce_new_order', $order->get_id(), $order );
+ } else {
+ do_action( 'woocommerce_update_order', $order->get_id(), $order );
+ }
+ }
+
+ /**
+ * Helper method that updates all the post meta for an order based on it's settings in the WC_Order class.
+ *
+ * @param WC_Order $order Order object.
+ * @since 3.0.0
+ */
+ protected function update_post_meta( &$order ) {
+ $updated_props = array();
+ $id = $order->get_id();
+ $meta_key_to_props = array(
+ '_order_key' => 'order_key',
+ '_customer_user' => 'customer_id',
+ '_payment_method' => 'payment_method',
+ '_payment_method_title' => 'payment_method_title',
+ '_transaction_id' => 'transaction_id',
+ '_customer_ip_address' => 'customer_ip_address',
+ '_customer_user_agent' => 'customer_user_agent',
+ '_created_via' => 'created_via',
+ '_date_completed' => 'date_completed',
+ '_date_paid' => 'date_paid',
+ '_cart_hash' => 'cart_hash',
+ );
+
+ $props_to_update = $this->get_props_to_update( $order, $meta_key_to_props );
+
+ foreach ( $props_to_update as $meta_key => $prop ) {
+ $value = $order->{"get_$prop"}( 'edit' );
+ $value = is_string( $value ) ? wp_slash( $value ) : $value;
+ switch ( $prop ) {
+ case 'date_paid':
+ case 'date_completed':
+ $value = ! is_null( $value ) ? $value->getTimestamp() : '';
+ break;
+ }
+
+ $updated = $this->update_or_delete_post_meta( $order, $meta_key, $value );
+
+ if ( $updated ) {
+ $updated_props[] = $prop;
+ }
+ }
+
+ $address_props = array(
+ 'billing' => array(
+ '_billing_first_name' => 'billing_first_name',
+ '_billing_last_name' => 'billing_last_name',
+ '_billing_company' => 'billing_company',
+ '_billing_address_1' => 'billing_address_1',
+ '_billing_address_2' => 'billing_address_2',
+ '_billing_city' => 'billing_city',
+ '_billing_state' => 'billing_state',
+ '_billing_postcode' => 'billing_postcode',
+ '_billing_country' => 'billing_country',
+ '_billing_email' => 'billing_email',
+ '_billing_phone' => 'billing_phone',
+ ),
+ 'shipping' => array(
+ '_shipping_first_name' => 'shipping_first_name',
+ '_shipping_last_name' => 'shipping_last_name',
+ '_shipping_company' => 'shipping_company',
+ '_shipping_address_1' => 'shipping_address_1',
+ '_shipping_address_2' => 'shipping_address_2',
+ '_shipping_city' => 'shipping_city',
+ '_shipping_state' => 'shipping_state',
+ '_shipping_postcode' => 'shipping_postcode',
+ '_shipping_country' => 'shipping_country',
+ ),
+ );
+
+ foreach ( $address_props as $props_key => $props ) {
+ $props_to_update = $this->get_props_to_update( $order, $props );
+ foreach ( $props_to_update as $meta_key => $prop ) {
+ $value = $order->{"get_$prop"}( 'edit' );
+ $value = is_string( $value ) ? wp_slash( $value ) : $value;
+ $updated = $this->update_or_delete_post_meta( $order, $meta_key, $value );
+
+ if ( $updated ) {
+ $updated_props[] = $prop;
+ $updated_props[] = $props_key;
+ }
+ }
+ }
+
+ parent::update_post_meta( $order );
+
+ // If address changed, store concatenated version to make searches faster.
+ if ( in_array( 'billing', $updated_props, true ) || ! metadata_exists( 'post', $id, '_billing_address_index' ) ) {
+ update_post_meta( $id, '_billing_address_index', implode( ' ', $order->get_address( 'billing' ) ) );
+ }
+ if ( in_array( 'shipping', $updated_props, true ) || ! metadata_exists( 'post', $id, '_shipping_address_index' ) ) {
+ update_post_meta( $id, '_shipping_address_index', implode( ' ', $order->get_address( 'shipping' ) ) );
+ }
+
+ // Legacy date handling. @todo remove in 4.0.
+ if ( in_array( 'date_paid', $updated_props, true ) ) {
+ $value = $order->get_date_paid( 'edit' );
+ // In 2.6.x date_paid was stored as _paid_date in local mysql format.
+ update_post_meta( $id, '_paid_date', ! is_null( $value ) ? $value->date( 'Y-m-d H:i:s' ) : '' );
+ }
+
+ if ( in_array( 'date_completed', $updated_props, true ) ) {
+ $value = $order->get_date_completed( 'edit' );
+ // In 2.6.x date_completed was stored as _completed_date in local mysql format.
+ update_post_meta( $id, '_completed_date', ! is_null( $value ) ? $value->date( 'Y-m-d H:i:s' ) : '' );
+ }
+
+ // If customer changed, update any downloadable permissions.
+ if ( in_array( 'customer_id', $updated_props ) || in_array( 'billing_email', $updated_props ) ) {
+ $data_store = WC_Data_Store::load( 'customer-download' );
+ $data_store->update_user_by_order_id( $id, $order->get_customer_id(), $order->get_billing_email() );
+ }
+
+ // Mark user account as active.
+ if ( in_array( 'customer_id', $updated_props, true ) ) {
+ wc_update_user_last_active( $order->get_customer_id() );
+ }
+
+ do_action( 'woocommerce_order_object_updated_props', $order, $updated_props );
+ }
+
+ /**
+ * Excerpt for post.
+ *
+ * @param WC_Order $order Order object.
+ * @return string
+ */
+ protected function get_post_excerpt( $order ) {
+ return $order->get_customer_note();
+ }
+
+ /**
+ * Get order key.
+ *
+ * @since 4.3.0
+ * @param WC_order $order Order object.
+ * @return string
+ */
+ protected function get_order_key( $order ) {
+ if ( '' !== $order->get_order_key() ) {
+ return $order->get_order_key();
+ }
+
+ return parent::get_order_key( $order );
+ }
+
+ /**
+ * Get amount already refunded.
+ *
+ * @param WC_Order $order Order object.
+ * @return float
+ */
+ public function get_total_refunded( $order ) {
+ global $wpdb;
+
+ $total = $wpdb->get_var(
+ $wpdb->prepare(
+ "SELECT SUM( postmeta.meta_value )
+ FROM $wpdb->postmeta AS postmeta
+ INNER JOIN $wpdb->posts AS posts ON ( posts.post_type = 'shop_order_refund' AND posts.post_parent = %d )
+ WHERE postmeta.meta_key = '_refund_amount'
+ AND postmeta.post_id = posts.ID",
+ $order->get_id()
+ )
+ );
+
+ return floatval( $total );
+ }
+
+ /**
+ * Get the total tax refunded.
+ *
+ * @param WC_Order $order Order object.
+ * @return float
+ */
+ public function get_total_tax_refunded( $order ) {
+ global $wpdb;
+
+ $total = $wpdb->get_var(
+ $wpdb->prepare(
+ "SELECT SUM( order_itemmeta.meta_value )
+ FROM {$wpdb->prefix}woocommerce_order_itemmeta AS order_itemmeta
+ INNER JOIN $wpdb->posts AS posts ON ( posts.post_type = 'shop_order_refund' AND posts.post_parent = %d )
+ INNER JOIN {$wpdb->prefix}woocommerce_order_items AS order_items ON ( order_items.order_id = posts.ID AND order_items.order_item_type = 'tax' )
+ WHERE order_itemmeta.order_item_id = order_items.order_item_id
+ AND order_itemmeta.meta_key IN ('tax_amount', 'shipping_tax_amount')",
+ $order->get_id()
+ )
+ );
+
+ return abs( $total );
+ }
+
+ /**
+ * Get the total shipping refunded.
+ *
+ * @param WC_Order $order Order object.
+ * @return float
+ */
+ public function get_total_shipping_refunded( $order ) {
+ global $wpdb;
+
+ $total = $wpdb->get_var(
+ $wpdb->prepare(
+ "SELECT SUM( order_itemmeta.meta_value )
+ FROM {$wpdb->prefix}woocommerce_order_itemmeta AS order_itemmeta
+ INNER JOIN $wpdb->posts AS posts ON ( posts.post_type = 'shop_order_refund' AND posts.post_parent = %d )
+ INNER JOIN {$wpdb->prefix}woocommerce_order_items AS order_items ON ( order_items.order_id = posts.ID AND order_items.order_item_type = 'shipping' )
+ WHERE order_itemmeta.order_item_id = order_items.order_item_id
+ AND order_itemmeta.meta_key IN ('cost')",
+ $order->get_id()
+ )
+ );
+
+ return abs( $total );
+ }
+
+ /**
+ * Finds an Order ID based on an order key.
+ *
+ * @param string $order_key An order key has generated by.
+ * @return int The ID of an order, or 0 if the order could not be found
+ */
+ public function get_order_id_by_order_key( $order_key ) {
+ global $wpdb;
+ return $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM {$wpdb->prefix}postmeta WHERE meta_key = '_order_key' AND meta_value = %s", $order_key ) );
+ }
+
+ /**
+ * Return count of orders with a specific status.
+ *
+ * @param string $status Order status. Function wc_get_order_statuses() returns a list of valid statuses.
+ * @return int
+ */
+ public function get_order_count( $status ) {
+ global $wpdb;
+ return absint( $wpdb->get_var( $wpdb->prepare( "SELECT COUNT( * ) FROM {$wpdb->posts} WHERE post_type = 'shop_order' AND post_status = %s", $status ) ) );
+ }
+
+ /**
+ * Get all orders matching the passed in args.
+ *
+ * @deprecated 3.1.0 - Use wc_get_orders instead.
+ * @see wc_get_orders()
+ *
+ * @param array $args List of args passed to wc_get_orders().
+ *
+ * @return array|object
+ */
+ public function get_orders( $args = array() ) {
+ wc_deprecated_function( 'WC_Order_Data_Store_CPT::get_orders', '3.1.0', 'Use wc_get_orders instead.' );
+ return wc_get_orders( $args );
+ }
+
+ /**
+ * Generate meta query for wc_get_orders.
+ *
+ * @param array $values List of customers ids or emails.
+ * @param string $relation 'or' or 'and' relation used to build the WP meta_query.
+ * @return array
+ */
+ private function get_orders_generate_customer_meta_query( $values, $relation = 'or' ) {
+ $meta_query = array(
+ 'relation' => strtoupper( $relation ),
+ 'customer_emails' => array(
+ 'key' => '_billing_email',
+ 'value' => array(),
+ 'compare' => 'IN',
+ ),
+ 'customer_ids' => array(
+ 'key' => '_customer_user',
+ 'value' => array(),
+ 'compare' => 'IN',
+ ),
+ );
+ foreach ( $values as $value ) {
+ if ( is_array( $value ) ) {
+ $query_part = $this->get_orders_generate_customer_meta_query( $value, 'and' );
+ if ( is_wp_error( $query_part ) ) {
+ return $query_part;
+ }
+ $meta_query[] = $query_part;
+ } elseif ( is_email( $value ) ) {
+ $meta_query['customer_emails']['value'][] = sanitize_email( $value );
+ } elseif ( is_numeric( $value ) ) {
+ $meta_query['customer_ids']['value'][] = strval( absint( $value ) );
+ } else {
+ return new WP_Error( 'woocommerce_query_invalid', __( 'Invalid customer query.', 'woocommerce' ), $values );
+ }
+ }
+
+ if ( empty( $meta_query['customer_emails']['value'] ) ) {
+ unset( $meta_query['customer_emails'] );
+ unset( $meta_query['relation'] );
+ }
+
+ if ( empty( $meta_query['customer_ids']['value'] ) ) {
+ unset( $meta_query['customer_ids'] );
+ unset( $meta_query['relation'] );
+ }
+
+ return $meta_query;
+ }
+
+ /**
+ * Get unpaid orders after a certain date,
+ *
+ * @param int $date Timestamp.
+ * @return array
+ */
+ public function get_unpaid_orders( $date ) {
+ global $wpdb;
+
+ $unpaid_orders = $wpdb->get_col(
+ $wpdb->prepare(
+ // @codingStandardsIgnoreStart
+ "SELECT posts.ID
+ FROM {$wpdb->posts} AS posts
+ WHERE posts.post_type IN ('" . implode( "','", wc_get_order_types() ) . "')
+ AND posts.post_status = 'wc-pending'
+ AND posts.post_modified < %s",
+ // @codingStandardsIgnoreEnd
+ gmdate( 'Y-m-d H:i:s', absint( $date ) )
+ )
+ );
+
+ return $unpaid_orders;
+ }
+
+ /**
+ * Search order data for a term and return ids.
+ *
+ * @param string $term Searched term.
+ * @return array of ids
+ */
+ public function search_orders( $term ) {
+ global $wpdb;
+
+ /**
+ * Searches on meta data can be slow - this lets you choose what fields to search.
+ * 3.0.0 added _billing_address and _shipping_address meta which contains all address data to make this faster.
+ * This however won't work on older orders unless updated, so search a few others (expand this using the filter if needed).
+ *
+ * @var array
+ */
+ $search_fields = array_map(
+ 'wc_clean',
+ apply_filters(
+ 'woocommerce_shop_order_search_fields',
+ array(
+ '_billing_address_index',
+ '_shipping_address_index',
+ '_billing_last_name',
+ '_billing_email',
+ )
+ )
+ );
+ $order_ids = array();
+
+ if ( is_numeric( $term ) ) {
+ $order_ids[] = absint( $term );
+ }
+
+ if ( ! empty( $search_fields ) ) {
+ $order_ids = array_unique(
+ array_merge(
+ $order_ids,
+ $wpdb->get_col(
+ $wpdb->prepare(
+ "SELECT DISTINCT p1.post_id FROM {$wpdb->postmeta} p1 WHERE p1.meta_value LIKE %s AND p1.meta_key IN ('" . implode( "','", array_map( 'esc_sql', $search_fields ) ) . "')", // @codingStandardsIgnoreLine
+ '%' . $wpdb->esc_like( wc_clean( $term ) ) . '%'
+ )
+ ),
+ $wpdb->get_col(
+ $wpdb->prepare(
+ "SELECT order_id
+ FROM {$wpdb->prefix}woocommerce_order_items as order_items
+ WHERE order_item_name LIKE %s",
+ '%' . $wpdb->esc_like( wc_clean( $term ) ) . '%'
+ )
+ )
+ )
+ );
+ }
+
+ return apply_filters( 'woocommerce_shop_order_search_results', $order_ids, $term, $search_fields );
+ }
+
+ /**
+ * Gets information about whether permissions were generated yet.
+ *
+ * @param WC_Order|int $order Order ID or order object.
+ * @return bool
+ */
+ public function get_download_permissions_granted( $order ) {
+ $order_id = WC_Order_Factory::get_order_id( $order );
+ return wc_string_to_bool( get_post_meta( $order_id, '_download_permissions_granted', true ) );
+ }
+
+ /**
+ * Stores information about whether permissions were generated yet.
+ *
+ * @param WC_Order|int $order Order ID or order object.
+ * @param bool $set True or false.
+ */
+ public function set_download_permissions_granted( $order, $set ) {
+ $order_id = WC_Order_Factory::get_order_id( $order );
+ update_post_meta( $order_id, '_download_permissions_granted', wc_bool_to_string( $set ) );
+ }
+
+ /**
+ * Gets information about whether sales were recorded.
+ *
+ * @param WC_Order|int $order Order ID or order object.
+ * @return bool
+ */
+ public function get_recorded_sales( $order ) {
+ $order_id = WC_Order_Factory::get_order_id( $order );
+ return wc_string_to_bool( get_post_meta( $order_id, '_recorded_sales', true ) );
+ }
+
+ /**
+ * Stores information about whether sales were recorded.
+ *
+ * @param WC_Order|int $order Order ID or order object.
+ * @param bool $set True or false.
+ */
+ public function set_recorded_sales( $order, $set ) {
+ $order_id = WC_Order_Factory::get_order_id( $order );
+ update_post_meta( $order_id, '_recorded_sales', wc_bool_to_string( $set ) );
+ }
+
+ /**
+ * Gets information about whether coupon counts were updated.
+ *
+ * @param WC_Order|int $order Order ID or order object.
+ * @return bool
+ */
+ public function get_recorded_coupon_usage_counts( $order ) {
+ $order_id = WC_Order_Factory::get_order_id( $order );
+ return wc_string_to_bool( get_post_meta( $order_id, '_recorded_coupon_usage_counts', true ) );
+ }
+
+ /**
+ * Stores information about whether coupon counts were updated.
+ *
+ * @param WC_Order|int $order Order ID or order object.
+ * @param bool $set True or false.
+ */
+ public function set_recorded_coupon_usage_counts( $order, $set ) {
+ $order_id = WC_Order_Factory::get_order_id( $order );
+ update_post_meta( $order_id, '_recorded_coupon_usage_counts', wc_bool_to_string( $set ) );
+ }
+
+ /**
+ * Return array of coupon_code => meta_key for coupon which have usage limit and have tentative keys.
+ * Pass $coupon_id if key for only one of the coupon is needed.
+ *
+ * @param WC_Order $order Order object.
+ * @param int $coupon_id If passed, will return held key for that coupon.
+ *
+ * @return array|string Key value pair for coupon code and meta key name. If $coupon_id is passed, returns meta_key for only that coupon.
+ */
+ public function get_coupon_held_keys( $order, $coupon_id = null ) {
+ $held_keys = $order->get_meta( '_coupon_held_keys' );
+ if ( $coupon_id ) {
+ return isset( $held_keys[ $coupon_id ] ) ? $held_keys[ $coupon_id ] : null;
+ }
+ return $held_keys;
+ }
+
+ /**
+ * Return array of coupon_code => meta_key for coupon which have usage limit per customer and have tentative keys.
+ *
+ * @param WC_Order $order Order object.
+ * @param int $coupon_id If passed, will return held key for that coupon.
+ *
+ * @return mixed
+ */
+ public function get_coupon_held_keys_for_users( $order, $coupon_id = null ) {
+ $held_keys_for_user = $order->get_meta( '_coupon_held_keys_for_users' );
+ if ( $coupon_id ) {
+ return isset( $held_keys_for_user[ $coupon_id ] ) ? $held_keys_for_user[ $coupon_id ] : null;
+ }
+ return $held_keys_for_user;
+ }
+
+ /**
+ * Add/Update list of meta keys that are currently being used by this order to hold a coupon.
+ * This is used to figure out what all meta entries we should delete when order is cancelled/completed.
+ *
+ * @param WC_Order $order Order object.
+ * @param array $held_keys Array of coupon_code => meta_key.
+ * @param array $held_keys_for_user Array of coupon_code => meta_key for held coupon for user.
+ *
+ * @return mixed
+ */
+ public function set_coupon_held_keys( $order, $held_keys, $held_keys_for_user ) {
+ if ( is_array( $held_keys ) && 0 < count( $held_keys ) ) {
+ $order->update_meta_data( '_coupon_held_keys', $held_keys );
+ }
+ if ( is_array( $held_keys_for_user ) && 0 < count( $held_keys_for_user ) ) {
+ $order->update_meta_data( '_coupon_held_keys_for_users', $held_keys_for_user );
+ }
+ }
+
+ /**
+ * Release all coupons held by this order.
+ *
+ * @param WC_Order $order Current order object.
+ * @param bool $save Whether to delete keys from DB right away. Could be useful to pass `false` if you are building a bulk request.
+ */
+ public function release_held_coupons( $order, $save = true ) {
+ $coupon_held_keys = $this->get_coupon_held_keys( $order );
+ if ( is_array( $coupon_held_keys ) ) {
+ foreach ( $coupon_held_keys as $coupon_id => $meta_key ) {
+ delete_post_meta( $coupon_id, $meta_key );
+ }
+ }
+ $order->delete_meta_data( '_coupon_held_keys' );
+
+ $coupon_held_keys_for_users = $this->get_coupon_held_keys_for_users( $order );
+ if ( is_array( $coupon_held_keys_for_users ) ) {
+ foreach ( $coupon_held_keys_for_users as $coupon_id => $meta_key ) {
+ delete_post_meta( $coupon_id, $meta_key );
+ }
+ }
+ $order->delete_meta_data( '_coupon_held_keys_for_users' );
+
+ if ( $save ) {
+ $order->save_meta_data();
+ }
+
+ }
+
+ /**
+ * Gets information about whether stock was reduced.
+ *
+ * @param WC_Order|int $order Order ID or order object.
+ * @return bool
+ */
+ public function get_stock_reduced( $order ) {
+ $order_id = WC_Order_Factory::get_order_id( $order );
+ return wc_string_to_bool( get_post_meta( $order_id, '_order_stock_reduced', true ) );
+ }
+
+ /**
+ * Stores information about whether stock was reduced.
+ *
+ * @param WC_Order|int $order Order ID or order object.
+ * @param bool $set True or false.
+ */
+ public function set_stock_reduced( $order, $set ) {
+ $order_id = WC_Order_Factory::get_order_id( $order );
+ update_post_meta( $order_id, '_order_stock_reduced', wc_bool_to_string( $set ) );
+ }
+
+ /**
+ * Get the order type based on Order ID.
+ *
+ * @since 3.0.0
+ * @param int $order_id Order ID.
+ * @return string
+ */
+ public function get_order_type( $order_id ) {
+ return get_post_type( $order_id );
+ }
+
+ /**
+ * Get valid WP_Query args from a WC_Order_Query's query variables.
+ *
+ * @since 3.1.0
+ * @param array $query_vars query vars from a WC_Order_Query.
+ * @return array
+ */
+ protected function get_wp_query_args( $query_vars ) {
+
+ // Map query vars to ones that get_wp_query_args or WP_Query recognize.
+ $key_mapping = array(
+ 'customer_id' => 'customer_user',
+ 'status' => 'post_status',
+ 'currency' => 'order_currency',
+ 'version' => 'order_version',
+ 'discount_total' => 'cart_discount',
+ 'discount_tax' => 'cart_discount_tax',
+ 'shipping_total' => 'order_shipping',
+ 'shipping_tax' => 'order_shipping_tax',
+ 'cart_tax' => 'order_tax',
+ 'total' => 'order_total',
+ 'page' => 'paged',
+ );
+
+ foreach ( $key_mapping as $query_key => $db_key ) {
+ if ( isset( $query_vars[ $query_key ] ) ) {
+ $query_vars[ $db_key ] = $query_vars[ $query_key ];
+ unset( $query_vars[ $query_key ] );
+ }
+ }
+
+ // Add the 'wc-' prefix to status if needed.
+ if ( ! empty( $query_vars['post_status'] ) ) {
+ if ( is_array( $query_vars['post_status'] ) ) {
+ foreach ( $query_vars['post_status'] as &$status ) {
+ $status = wc_is_order_status( 'wc-' . $status ) ? 'wc-' . $status : $status;
+ }
+ } else {
+ $query_vars['post_status'] = wc_is_order_status( 'wc-' . $query_vars['post_status'] ) ? 'wc-' . $query_vars['post_status'] : $query_vars['post_status'];
+ }
+ }
+
+ $wp_query_args = parent::get_wp_query_args( $query_vars );
+
+ if ( ! isset( $wp_query_args['date_query'] ) ) {
+ $wp_query_args['date_query'] = array();
+ }
+ if ( ! isset( $wp_query_args['meta_query'] ) ) {
+ $wp_query_args['meta_query'] = array();
+ }
+
+ $date_queries = array(
+ 'date_created' => 'post_date',
+ 'date_modified' => 'post_modified',
+ 'date_completed' => '_date_completed',
+ 'date_paid' => '_date_paid',
+ );
+ foreach ( $date_queries as $query_var_key => $db_key ) {
+ if ( isset( $query_vars[ $query_var_key ] ) && '' !== $query_vars[ $query_var_key ] ) {
+
+ // Remove any existing meta queries for the same keys to prevent conflicts.
+ $existing_queries = wp_list_pluck( $wp_query_args['meta_query'], 'key', true );
+ $meta_query_index = array_search( $db_key, $existing_queries, true );
+ if ( false !== $meta_query_index ) {
+ unset( $wp_query_args['meta_query'][ $meta_query_index ] );
+ }
+
+ $wp_query_args = $this->parse_date_for_wp_query( $query_vars[ $query_var_key ], $db_key, $wp_query_args );
+ }
+ }
+
+ if ( isset( $query_vars['customer'] ) && '' !== $query_vars['customer'] && array() !== $query_vars['customer'] ) {
+ $values = is_array( $query_vars['customer'] ) ? $query_vars['customer'] : array( $query_vars['customer'] );
+ $customer_query = $this->get_orders_generate_customer_meta_query( $values );
+ if ( is_wp_error( $customer_query ) ) {
+ $wp_query_args['errors'][] = $customer_query;
+ } else {
+ $wp_query_args['meta_query'][] = $customer_query;
+ }
+ }
+
+ if ( isset( $query_vars['anonymized'] ) ) {
+ if ( $query_vars['anonymized'] ) {
+ $wp_query_args['meta_query'][] = array(
+ 'key' => '_anonymized',
+ 'value' => 'yes',
+ );
+ } else {
+ $wp_query_args['meta_query'][] = array(
+ 'key' => '_anonymized',
+ 'compare' => 'NOT EXISTS',
+ );
+ }
+ }
+
+ if ( ! isset( $query_vars['paginate'] ) || ! $query_vars['paginate'] ) {
+ $wp_query_args['no_found_rows'] = true;
+ }
+
+ return apply_filters( 'woocommerce_order_data_store_cpt_get_orders_query', $wp_query_args, $query_vars, $this );
+ }
+
+ /**
+ * Query for Orders matching specific criteria.
+ *
+ * @since 3.1.0
+ *
+ * @param array $query_vars query vars from a WC_Order_Query.
+ *
+ * @return array|object
+ */
+ public function query( $query_vars ) {
+ $args = $this->get_wp_query_args( $query_vars );
+
+ if ( ! empty( $args['errors'] ) ) {
+ $query = (object) array(
+ 'posts' => array(),
+ 'found_posts' => 0,
+ 'max_num_pages' => 0,
+ );
+ } else {
+ $query = new WP_Query( $args );
+ }
+
+ $orders = ( isset( $query_vars['return'] ) && 'ids' === $query_vars['return'] ) ? $query->posts : array_filter( array_map( 'wc_get_order', $query->posts ) );
+
+ if ( isset( $query_vars['paginate'] ) && $query_vars['paginate'] ) {
+ return (object) array(
+ 'orders' => $orders,
+ 'total' => $query->found_posts,
+ 'max_num_pages' => $query->max_num_pages,
+ );
+ }
+
+ return $orders;
+ }
+
+ /**
+ * Return the order type of a given item which belongs to WC_Order.
+ *
+ * @since 3.2.0
+ * @param WC_Order $order Order Object.
+ * @param int $order_item_id Order item id.
+ * @return string Order Item type
+ */
+ public function get_order_item_type( $order, $order_item_id ) {
+ global $wpdb;
+ return $wpdb->get_var( $wpdb->prepare( "SELECT DISTINCT order_item_type FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d and order_item_id = %d;", $order->get_id(), $order_item_id ) );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-item-coupon-data-store.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-item-coupon-data-store.php
new file mode 100644
index 0000000..01eeb9d
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-item-coupon-data-store.php
@@ -0,0 +1,62 @@
+get_id();
+ $item->set_props(
+ array(
+ 'discount' => get_metadata( 'order_item', $id, 'discount_amount', true ),
+ 'discount_tax' => get_metadata( 'order_item', $id, 'discount_amount_tax', true ),
+ )
+ );
+ $item->set_object_read( true );
+ }
+
+ /**
+ * Saves an item's data to the database / item meta.
+ * Ran after both create and update, so $item->get_id() will be set.
+ *
+ * @since 3.0.0
+ * @param WC_Order_Item_Coupon $item Coupon order item.
+ */
+ public function save_item_data( &$item ) {
+ $id = $item->get_id();
+ $save_values = array(
+ 'discount_amount' => $item->get_discount( 'edit' ),
+ 'discount_amount_tax' => $item->get_discount_tax( 'edit' ),
+ );
+ foreach ( $save_values as $key => $value ) {
+ update_metadata( 'order_item', $id, $key, $value );
+ }
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-item-data-store.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-item-data-store.php
new file mode 100644
index 0000000..46600ac
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-item-data-store.php
@@ -0,0 +1,189 @@
+insert(
+ $wpdb->prefix . 'woocommerce_order_items',
+ array(
+ 'order_item_name' => $item['order_item_name'],
+ 'order_item_type' => $item['order_item_type'],
+ 'order_id' => $order_id,
+ ),
+ array(
+ '%s',
+ '%s',
+ '%d',
+ )
+ );
+
+ $item_id = absint( $wpdb->insert_id );
+
+ $this->clear_caches( $item_id, $order_id );
+
+ return $item_id;
+ }
+
+ /**
+ * Update an order item.
+ *
+ * @since 3.0.0
+ * @param int $item_id Item ID.
+ * @param array $item order_item_name or order_item_type.
+ * @return boolean
+ */
+ public function update_order_item( $item_id, $item ) {
+ global $wpdb;
+ $updated = $wpdb->update( $wpdb->prefix . 'woocommerce_order_items', $item, array( 'order_item_id' => $item_id ) );
+ $this->clear_caches( $item_id, null );
+ return $updated;
+ }
+
+ /**
+ * Delete an order item.
+ *
+ * @since 3.0.0
+ * @param int $item_id Item ID.
+ */
+ public function delete_order_item( $item_id ) {
+ // Load the order ID before the deletion, since after, it won't exist in the database.
+ $order_id = $this->get_order_id_by_order_item_id( $item_id );
+
+ global $wpdb;
+ $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_item_id = %d", $item_id ) );
+ $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id = %d", $item_id ) );
+
+ $this->clear_caches( $item_id, $order_id );
+ }
+
+ /**
+ * Update term meta.
+ *
+ * @since 3.0.0
+ * @param int $item_id Item ID.
+ * @param string $meta_key Meta key.
+ * @param mixed $meta_value Meta value.
+ * @param string $prev_value (default: '').
+ * @return bool
+ */
+ public function update_metadata( $item_id, $meta_key, $meta_value, $prev_value = '' ) {
+ return update_metadata( 'order_item', $item_id, $meta_key, is_string( $meta_value ) ? wp_slash( $meta_value ) : $meta_value, $prev_value );
+ }
+
+ /**
+ * Add term meta.
+ *
+ * @since 3.0.0
+ * @param int $item_id Item ID.
+ * @param string $meta_key Meta key.
+ * @param mixed $meta_value Meta value.
+ * @param bool $unique (default: false).
+ * @return int New row ID or 0
+ */
+ public function add_metadata( $item_id, $meta_key, $meta_value, $unique = false ) {
+ return add_metadata( 'order_item', $item_id, wp_slash( $meta_key ), is_string( $meta_value ) ? wp_slash( $meta_value ) : $meta_value, $unique );
+ }
+
+ /**
+ * Delete term meta.
+ *
+ * @since 3.0.0
+ * @param int $item_id Item ID.
+ * @param string $meta_key Meta key.
+ * @param string $meta_value (default: '').
+ * @param bool $delete_all (default: false).
+ * @return bool
+ */
+ public function delete_metadata( $item_id, $meta_key, $meta_value = '', $delete_all = false ) {
+ return delete_metadata( 'order_item', $item_id, $meta_key, is_string( $meta_value ) ? wp_slash( $meta_value ) : $meta_value, $delete_all );
+ }
+
+ /**
+ * Get term meta.
+ *
+ * @since 3.0.0
+ * @param int $item_id Item ID.
+ * @param string $key Meta key.
+ * @param bool $single (default: true).
+ * @return mixed
+ */
+ public function get_metadata( $item_id, $key, $single = true ) {
+ return get_metadata( 'order_item', $item_id, $key, $single );
+ }
+
+ /**
+ * Get order ID by order item ID.
+ *
+ * @since 3.0.0
+ * @param int $item_id Item ID.
+ * @return int
+ */
+ public function get_order_id_by_order_item_id( $item_id ) {
+ global $wpdb;
+ return (int) $wpdb->get_var(
+ $wpdb->prepare(
+ "SELECT order_id FROM {$wpdb->prefix}woocommerce_order_items WHERE order_item_id = %d",
+ $item_id
+ )
+ );
+ }
+
+ /**
+ * Get the order item type based on Item ID.
+ *
+ * @since 3.0.0
+ * @param int $item_id Item ID.
+ * @return string|null Order item type or null if no order item entry found.
+ */
+ public function get_order_item_type( $item_id ) {
+ global $wpdb;
+ $order_item_type = $wpdb->get_var(
+ $wpdb->prepare(
+ "SELECT order_item_type FROM {$wpdb->prefix}woocommerce_order_items WHERE order_item_id = %d LIMIT 1;",
+ $item_id
+ )
+ );
+
+ return $order_item_type;
+ }
+
+ /**
+ * Clear meta cache.
+ *
+ * @param int $item_id Item ID.
+ * @param int|null $order_id Order ID. If not set, it will be loaded using the item ID.
+ */
+ protected function clear_caches( $item_id, $order_id ) {
+ wp_cache_delete( 'item-' . $item_id, 'order-items' );
+
+ if ( ! $order_id ) {
+ $order_id = $this->get_order_id_by_order_item_id( $item_id );
+ }
+ if ( $order_id ) {
+ wp_cache_delete( 'order-items-' . $order_id, 'orders' );
+ }
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-item-fee-data-store.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-item-fee-data-store.php
new file mode 100644
index 0000000..2222d06
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-item-fee-data-store.php
@@ -0,0 +1,69 @@
+get_id();
+ $item->set_props(
+ array(
+ 'amount' => get_metadata( 'order_item', $id, '_fee_amount', true ),
+ 'tax_class' => get_metadata( 'order_item', $id, '_tax_class', true ),
+ 'tax_status' => get_metadata( 'order_item', $id, '_tax_status', true ),
+ 'total' => get_metadata( 'order_item', $id, '_line_total', true ),
+ 'taxes' => get_metadata( 'order_item', $id, '_line_tax_data', true ),
+ )
+ );
+ $item->set_object_read( true );
+ }
+
+ /**
+ * Saves an item's data to the database / item meta.
+ * Ran after both create and update, so $id will be set.
+ *
+ * @since 3.0.0
+ * @param WC_Order_Item_Fee $item Fee order item object.
+ */
+ public function save_item_data( &$item ) {
+ $id = $item->get_id();
+ $save_values = array(
+ '_fee_amount' => $item->get_amount( 'edit' ),
+ '_tax_class' => $item->get_tax_class( 'edit' ),
+ '_tax_status' => $item->get_tax_status( 'edit' ),
+ '_line_total' => $item->get_total( 'edit' ),
+ '_line_tax' => $item->get_total_tax( 'edit' ),
+ '_line_tax_data' => $item->get_taxes( 'edit' ),
+ );
+ foreach ( $save_values as $key => $value ) {
+ update_metadata( 'order_item', $id, $key, $value );
+ }
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-item-product-data-store.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-item-product-data-store.php
new file mode 100644
index 0000000..2f78691
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-item-product-data-store.php
@@ -0,0 +1,97 @@
+get_id();
+ $item->set_props(
+ array(
+ 'product_id' => get_metadata( 'order_item', $id, '_product_id', true ),
+ 'variation_id' => get_metadata( 'order_item', $id, '_variation_id', true ),
+ 'quantity' => get_metadata( 'order_item', $id, '_qty', true ),
+ 'tax_class' => get_metadata( 'order_item', $id, '_tax_class', true ),
+ 'subtotal' => get_metadata( 'order_item', $id, '_line_subtotal', true ),
+ 'total' => get_metadata( 'order_item', $id, '_line_total', true ),
+ 'taxes' => get_metadata( 'order_item', $id, '_line_tax_data', true ),
+ )
+ );
+ $item->set_object_read( true );
+ }
+
+ /**
+ * Saves an item's data to the database / item meta.
+ * Ran after both create and update, so $id will be set.
+ *
+ * @since 3.0.0
+ * @param WC_Order_Item_Product $item Product order item object.
+ */
+ public function save_item_data( &$item ) {
+ $id = $item->get_id();
+ $changes = $item->get_changes();
+ $meta_key_to_props = array(
+ '_product_id' => 'product_id',
+ '_variation_id' => 'variation_id',
+ '_qty' => 'quantity',
+ '_tax_class' => 'tax_class',
+ '_line_subtotal' => 'subtotal',
+ '_line_subtotal_tax' => 'subtotal_tax',
+ '_line_total' => 'total',
+ '_line_tax' => 'total_tax',
+ '_line_tax_data' => 'taxes',
+ );
+ $props_to_update = $this->get_props_to_update( $item, $meta_key_to_props, 'order_item' );
+
+ foreach ( $props_to_update as $meta_key => $prop ) {
+ update_metadata( 'order_item', $id, $meta_key, $item->{"get_$prop"}( 'edit' ) );
+ }
+ }
+
+ /**
+ * Get a list of download IDs for a specific item from an order.
+ *
+ * @since 3.0.0
+ * @param WC_Order_Item_Product $item Product order item object.
+ * @param WC_Order $order Order object.
+ * @return array
+ */
+ public function get_download_ids( $item, $order ) {
+ global $wpdb;
+ return $wpdb->get_col(
+ $wpdb->prepare(
+ "SELECT download_id FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE user_email = %s AND order_key = %s AND product_id = %d ORDER BY permission_id",
+ $order->get_billing_email(),
+ $order->get_order_key(),
+ $item->get_variation_id() ? $item->get_variation_id() : $item->get_product_id()
+ )
+ );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-item-shipping-data-store.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-item-shipping-data-store.php
new file mode 100644
index 0000000..0c4f343
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-item-shipping-data-store.php
@@ -0,0 +1,78 @@
+get_id();
+ $item->set_props(
+ array(
+ 'method_id' => get_metadata( 'order_item', $id, 'method_id', true ),
+ 'instance_id' => get_metadata( 'order_item', $id, 'instance_id', true ),
+ 'total' => get_metadata( 'order_item', $id, 'cost', true ),
+ 'taxes' => get_metadata( 'order_item', $id, 'taxes', true ),
+ )
+ );
+
+ // BW compat.
+ if ( '' === $item->get_instance_id() && strstr( $item->get_method_id(), ':' ) ) {
+ $legacy_method_id = explode( ':', $item->get_method_id() );
+ $item->set_method_id( $legacy_method_id[0] );
+ $item->set_instance_id( $legacy_method_id[1] );
+ }
+
+ $item->set_object_read( true );
+ }
+
+ /**
+ * Saves an item's data to the database / item meta.
+ * Ran after both create and update, so $id will be set.
+ *
+ * @since 3.0.0
+ * @param WC_Order_Item_Shipping $item Item to save.
+ */
+ public function save_item_data( &$item ) {
+ $id = $item->get_id();
+ $changes = $item->get_changes();
+ $meta_key_to_props = array(
+ 'method_id' => 'method_id',
+ 'instance_id' => 'instance_id',
+ 'cost' => 'total',
+ 'total_tax' => 'total_tax',
+ 'taxes' => 'taxes',
+ );
+ $props_to_update = $this->get_props_to_update( $item, $meta_key_to_props, 'order_item' );
+
+ foreach ( $props_to_update as $meta_key => $prop ) {
+ update_metadata( 'order_item', $id, $meta_key, $item->{"get_$prop"}( 'edit' ) );
+ }
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-item-tax-data-store.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-item-tax-data-store.php
new file mode 100644
index 0000000..ab5325a
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-item-tax-data-store.php
@@ -0,0 +1,74 @@
+get_id();
+ $item->set_props(
+ array(
+ 'rate_id' => get_metadata( 'order_item', $id, 'rate_id', true ),
+ 'label' => get_metadata( 'order_item', $id, 'label', true ),
+ 'compound' => get_metadata( 'order_item', $id, 'compound', true ),
+ 'tax_total' => get_metadata( 'order_item', $id, 'tax_amount', true ),
+ 'shipping_tax_total' => get_metadata( 'order_item', $id, 'shipping_tax_amount', true ),
+ 'rate_percent' => get_metadata( 'order_item', $id, 'rate_percent', true ),
+ )
+ );
+ $item->set_object_read( true );
+ }
+
+ /**
+ * Saves an item's data to the database / item meta.
+ * Ran after both create and update, so $id will be set.
+ *
+ * @since 3.0.0
+ * @param WC_Order_Item_Tax $item Tax order item object.
+ */
+ public function save_item_data( &$item ) {
+ $id = $item->get_id();
+ $changes = $item->get_changes();
+ $meta_key_to_props = array(
+ 'rate_id' => 'rate_id',
+ 'label' => 'label',
+ 'compound' => 'compound',
+ 'tax_amount' => 'tax_total',
+ 'shipping_tax_amount' => 'shipping_tax_total',
+ 'rate_percent' => 'rate_percent',
+ );
+ $props_to_update = $this->get_props_to_update( $item, $meta_key_to_props, 'order_item' );
+
+ foreach ( $props_to_update as $meta_key => $prop ) {
+ update_metadata( 'order_item', $id, $meta_key, $item->{"get_$prop"}( 'edit' ) );
+ }
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-refund-data-store-cpt.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-refund-data-store-cpt.php
new file mode 100644
index 0000000..1cee50a
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-order-refund-data-store-cpt.php
@@ -0,0 +1,119 @@
+get_id();
+
+ if ( ! $id ) {
+ return;
+ }
+
+ wp_delete_post( $id );
+ $order->set_id( 0 );
+ do_action( 'woocommerce_delete_order_refund', $id );
+ }
+
+ /**
+ * Read refund data. Can be overridden by child classes to load other props.
+ *
+ * @param WC_Order_Refund $refund Refund object.
+ * @param object $post_object Post object.
+ * @since 3.0.0
+ */
+ protected function read_order_data( &$refund, $post_object ) {
+ parent::read_order_data( $refund, $post_object );
+ $id = $refund->get_id();
+ $refund->set_props(
+ array(
+ 'amount' => get_post_meta( $id, '_refund_amount', true ),
+ 'refunded_by' => metadata_exists( 'post', $id, '_refunded_by' ) ? get_post_meta( $id, '_refunded_by', true ) : absint( $post_object->post_author ),
+ 'refunded_payment' => wc_string_to_bool( get_post_meta( $id, '_refunded_payment', true ) ),
+ 'reason' => metadata_exists( 'post', $id, '_refund_reason' ) ? get_post_meta( $id, '_refund_reason', true ) : $post_object->post_excerpt,
+ )
+ );
+ }
+
+ /**
+ * Helper method that updates all the post meta for an order based on it's settings in the WC_Order class.
+ *
+ * @param WC_Order_Refund $refund Refund object.
+ * @since 3.0.0
+ */
+ protected function update_post_meta( &$refund ) {
+ parent::update_post_meta( $refund );
+
+ $updated_props = array();
+ $meta_key_to_props = array(
+ '_refund_amount' => 'amount',
+ '_refunded_by' => 'refunded_by',
+ '_refunded_payment' => 'refunded_payment',
+ '_refund_reason' => 'reason',
+ );
+
+ $props_to_update = $this->get_props_to_update( $refund, $meta_key_to_props );
+ foreach ( $props_to_update as $meta_key => $prop ) {
+ $value = $refund->{"get_$prop"}( 'edit' );
+ update_post_meta( $refund->get_id(), $meta_key, $value );
+ $updated_props[] = $prop;
+ }
+
+ do_action( 'woocommerce_order_refund_object_updated_props', $refund, $updated_props );
+ }
+
+ /**
+ * Get a title for the new post type.
+ *
+ * @return string
+ */
+ protected function get_post_title() {
+ return sprintf(
+ /* translators: %s: Order date */
+ __( 'Refund – %s', 'woocommerce' ),
+ strftime( _x( '%b %d, %Y @ %I:%M %p', 'Order date parsed by strftime', 'woocommerce' ) ) // phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment, WordPress.WP.I18n.UnorderedPlaceholdersText
+ );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-payment-token-data-store.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-payment-token-data-store.php
new file mode 100644
index 0000000..81e2211
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-payment-token-data-store.php
@@ -0,0 +1,372 @@
+validate() ) {
+ throw new Exception( __( 'Invalid or missing payment token fields.', 'woocommerce' ) );
+ }
+
+ global $wpdb;
+ if ( ! $token->is_default() && $token->get_user_id() > 0 ) {
+ $default_token = WC_Payment_Tokens::get_customer_default_token( $token->get_user_id() );
+ if ( is_null( $default_token ) ) {
+ $token->set_default( true );
+ }
+ }
+
+ $payment_token_data = array(
+ 'gateway_id' => $token->get_gateway_id( 'edit' ),
+ 'token' => $token->get_token( 'edit' ),
+ 'user_id' => $token->get_user_id( 'edit' ),
+ 'type' => $token->get_type( 'edit' ),
+ );
+
+ $wpdb->insert( $wpdb->prefix . 'woocommerce_payment_tokens', $payment_token_data );
+ $token_id = $wpdb->insert_id;
+ $token->set_id( $token_id );
+ $this->save_extra_data( $token, true );
+ $token->save_meta_data();
+ $token->apply_changes();
+
+ // Make sure all other tokens are not set to default.
+ if ( $token->is_default() && $token->get_user_id() > 0 ) {
+ WC_Payment_Tokens::set_users_default( $token->get_user_id(), $token_id );
+ }
+
+ do_action( 'woocommerce_new_payment_token', $token_id, $token );
+ }
+
+ /**
+ * Update a payment token.
+ *
+ * @since 3.0.0
+ *
+ * @param WC_Payment_Token $token Payment token object.
+ *
+ * @throws Exception Throw exception if invalid or missing payment token fields.
+ */
+ public function update( &$token ) {
+ if ( false === $token->validate() ) {
+ throw new Exception( __( 'Invalid or missing payment token fields.', 'woocommerce' ) );
+ }
+
+ global $wpdb;
+
+ $updated_props = array();
+ $core_props = array( 'gateway_id', 'token', 'user_id', 'type' );
+ $changed_props = array_keys( $token->get_changes() );
+
+ foreach ( $changed_props as $prop ) {
+ if ( ! in_array( $prop, $core_props, true ) ) {
+ continue;
+ }
+ $updated_props[] = $prop;
+ $payment_token_data[ $prop ] = $token->{'get_' . $prop}( 'edit' );
+ }
+
+ if ( ! empty( $payment_token_data ) ) {
+ $wpdb->update(
+ $wpdb->prefix . 'woocommerce_payment_tokens',
+ $payment_token_data,
+ array( 'token_id' => $token->get_id() )
+ );
+ }
+
+ $updated_extra_props = $this->save_extra_data( $token );
+ $updated_props = array_merge( $updated_props, $updated_extra_props );
+ $token->save_meta_data();
+ $token->apply_changes();
+
+ // Make sure all other tokens are not set to default.
+ if ( $token->is_default() && $token->get_user_id() > 0 ) {
+ WC_Payment_Tokens::set_users_default( $token->get_user_id(), $token->get_id() );
+ }
+
+ do_action( 'woocommerce_payment_token_object_updated_props', $token, $updated_props );
+ do_action( 'woocommerce_payment_token_updated', $token->get_id() );
+ }
+
+ /**
+ * Remove a payment token from the database.
+ *
+ * @since 3.0.0
+ * @param WC_Payment_Token $token Payment token object.
+ * @param bool $force_delete Unused param.
+ */
+ public function delete( &$token, $force_delete = false ) {
+ global $wpdb;
+ $wpdb->delete( $wpdb->prefix . 'woocommerce_payment_tokens', array( 'token_id' => $token->get_id() ), array( '%d' ) );
+ $wpdb->delete( $wpdb->prefix . 'woocommerce_payment_tokenmeta', array( 'payment_token_id' => $token->get_id() ), array( '%d' ) );
+ do_action( 'woocommerce_payment_token_deleted', $token->get_id(), $token );
+ }
+
+ /**
+ * Read a token from the database.
+ *
+ * @since 3.0.0
+ *
+ * @param WC_Payment_Token $token Payment token object.
+ *
+ * @throws Exception Throw exception if invalid payment token.
+ */
+ public function read( &$token ) {
+ global $wpdb;
+
+ $data = $wpdb->get_row(
+ $wpdb->prepare(
+ "SELECT token, user_id, gateway_id, is_default FROM {$wpdb->prefix}woocommerce_payment_tokens WHERE token_id = %d LIMIT 1",
+ $token->get_id()
+ )
+ );
+
+ if ( $data ) {
+ $token->set_props(
+ array(
+ 'token' => $data->token,
+ 'user_id' => $data->user_id,
+ 'gateway_id' => $data->gateway_id,
+ 'default' => $data->is_default,
+ )
+ );
+ $this->read_extra_data( $token );
+ $token->read_meta_data();
+ $token->set_object_read( true );
+ do_action( 'woocommerce_payment_token_loaded', $token );
+ } else {
+ throw new Exception( __( 'Invalid payment token.', 'woocommerce' ) );
+ }
+ }
+
+ /**
+ * Read extra data associated with the token (like last4 digits of a card for expiry dates).
+ *
+ * @param WC_Payment_Token $token Payment token object.
+ * @since 3.0.0
+ */
+ protected function read_extra_data( &$token ) {
+ foreach ( $token->get_extra_data_keys() as $key ) {
+ $function = 'set_' . $key;
+ if ( is_callable( array( $token, $function ) ) ) {
+ $token->{$function}( get_metadata( 'payment_token', $token->get_id(), $key, true ) );
+ }
+ }
+ }
+
+ /**
+ * Saves extra token data as meta.
+ *
+ * @since 3.0.0
+ * @param WC_Payment_Token $token Payment token object.
+ * @param bool $force By default, only changed props are updated. When this param is true all props are updated.
+ * @return array List of updated props.
+ */
+ protected function save_extra_data( &$token, $force = false ) {
+ if ( $this->extra_data_saved ) {
+ return array();
+ }
+
+ $updated_props = array();
+ $extra_data_keys = $token->get_extra_data_keys();
+ $meta_key_to_props = ! empty( $extra_data_keys ) ? array_combine( $extra_data_keys, $extra_data_keys ) : array();
+ $props_to_update = $force ? $meta_key_to_props : $this->get_props_to_update( $token, $meta_key_to_props );
+
+ foreach ( $extra_data_keys as $key ) {
+ if ( ! array_key_exists( $key, $props_to_update ) ) {
+ continue;
+ }
+ $function = 'get_' . $key;
+ if ( is_callable( array( $token, $function ) ) ) {
+ if ( update_metadata( 'payment_token', $token->get_id(), $key, $token->{$function}( 'edit' ) ) ) {
+ $updated_props[] = $key;
+ }
+ }
+ }
+
+ return $updated_props;
+ }
+
+ /**
+ * Returns an array of objects (stdObject) matching specific token criteria.
+ * Accepts token_id, user_id, gateway_id, and type.
+ * Each object should contain the fields token_id, gateway_id, token, user_id, type, is_default.
+ *
+ * @since 3.0.0
+ * @param array $args List of accepted args: token_id, gateway_id, user_id, type.
+ * @return array
+ */
+ public function get_tokens( $args ) {
+ global $wpdb;
+ $args = wp_parse_args(
+ $args,
+ array(
+ 'token_id' => '',
+ 'user_id' => '',
+ 'gateway_id' => '',
+ 'type' => '',
+ )
+ );
+
+ $sql = "SELECT * FROM {$wpdb->prefix}woocommerce_payment_tokens";
+ $where = array( '1=1' );
+
+ if ( $args['token_id'] ) {
+ $token_ids = array_map( 'absint', is_array( $args['token_id'] ) ? $args['token_id'] : array( $args['token_id'] ) );
+ $where[] = "token_id IN ('" . implode( "','", array_map( 'esc_sql', $token_ids ) ) . "')";
+ }
+
+ if ( $args['user_id'] ) {
+ $where[] = $wpdb->prepare( 'user_id = %d', absint( $args['user_id'] ) );
+ }
+
+ if ( $args['gateway_id'] ) {
+ $gateway_ids = array( $args['gateway_id'] );
+ } else {
+ $gateways = WC_Payment_Gateways::instance();
+ $gateway_ids = $gateways->get_payment_gateway_ids();
+ }
+
+ $page = isset( $args['page'] ) ? absint( $args['page'] ) : 1;
+ $posts_per_page = isset( $args['limit'] ) ? absint( $args['limit'] ) : get_option( 'posts_per_page' );
+
+ $pgstrt = absint( ( $page - 1 ) * $posts_per_page ) . ', ';
+ $limits = 'LIMIT ' . $pgstrt . $posts_per_page;
+
+ $gateway_ids[] = '';
+ $where[] = "gateway_id IN ('" . implode( "','", array_map( 'esc_sql', $gateway_ids ) ) . "')";
+
+ if ( $args['type'] ) {
+ $where[] = $wpdb->prepare( 'type = %s', $args['type'] );
+ }
+
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
+ $token_results = $wpdb->get_results( $sql . ' WHERE ' . implode( ' AND ', $where ) . ' ' . $limits );
+
+ return $token_results;
+ }
+
+ /**
+ * Returns an stdObject of a token for a user's default token.
+ * Should contain the fields token_id, gateway_id, token, user_id, type, is_default.
+ *
+ * @since 3.0.0
+ * @param int $user_id User ID.
+ * @return object
+ */
+ public function get_users_default_token( $user_id ) {
+ global $wpdb;
+ return $wpdb->get_row(
+ $wpdb->prepare(
+ "SELECT * FROM {$wpdb->prefix}woocommerce_payment_tokens WHERE user_id = %d AND is_default = 1",
+ $user_id
+ )
+ );
+ }
+
+ /**
+ * Returns an stdObject of a token.
+ * Should contain the fields token_id, gateway_id, token, user_id, type, is_default.
+ *
+ * @since 3.0.0
+ * @param id $token_id Token ID.
+ * @return object
+ */
+ public function get_token_by_id( $token_id ) {
+ global $wpdb;
+ return $wpdb->get_row(
+ $wpdb->prepare(
+ "SELECT * FROM {$wpdb->prefix}woocommerce_payment_tokens WHERE token_id = %d",
+ $token_id
+ )
+ );
+ }
+
+ /**
+ * Returns metadata for a specific payment token.
+ *
+ * @since 3.0.0
+ * @param id $token_id Token ID.
+ * @return array
+ */
+ public function get_metadata( $token_id ) {
+ return get_metadata( 'payment_token', $token_id );
+ }
+
+ /**
+ * Get a token's type by ID.
+ *
+ * @since 3.0.0
+ * @param id $token_id Token ID.
+ * @return string
+ */
+ public function get_token_type_by_id( $token_id ) {
+ global $wpdb;
+ return $wpdb->get_var(
+ $wpdb->prepare(
+ "SELECT type FROM {$wpdb->prefix}woocommerce_payment_tokens WHERE token_id = %d",
+ $token_id
+ )
+ );
+ }
+
+ /**
+ * Update's a tokens default status in the database. Used for quickly
+ * looping through tokens and setting their statuses instead of creating a bunch
+ * of objects.
+ *
+ * @since 3.0.0
+ *
+ * @param id $token_id Token ID.
+ * @param bool $status Whether given payment token is the default payment token or not.
+ *
+ * @return void
+ */
+ public function set_default_status( $token_id, $status = true ) {
+ global $wpdb;
+ $wpdb->update(
+ $wpdb->prefix . 'woocommerce_payment_tokens',
+ array( 'is_default' => $status ),
+ array(
+ 'token_id' => $token_id,
+ )
+ );
+ }
+
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-product-data-store-cpt.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-product-data-store-cpt.php
new file mode 100644
index 0000000..9e56908
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-product-data-store-cpt.php
@@ -0,0 +1,2101 @@
+get_date_created( 'edit' ) ) {
+ $product->set_date_created( time() );
+ }
+
+ $id = wp_insert_post(
+ apply_filters(
+ 'woocommerce_new_product_data',
+ array(
+ 'post_type' => 'product',
+ 'post_status' => $product->get_status() ? $product->get_status() : 'publish',
+ 'post_author' => get_current_user_id(),
+ 'post_title' => $product->get_name() ? $product->get_name() : __( 'Product', 'woocommerce' ),
+ 'post_content' => $product->get_description(),
+ 'post_excerpt' => $product->get_short_description(),
+ 'post_parent' => $product->get_parent_id(),
+ 'comment_status' => $product->get_reviews_allowed() ? 'open' : 'closed',
+ 'ping_status' => 'closed',
+ 'menu_order' => $product->get_menu_order(),
+ 'post_password' => $product->get_post_password( 'edit' ),
+ 'post_date' => gmdate( 'Y-m-d H:i:s', $product->get_date_created( 'edit' )->getOffsetTimestamp() ),
+ 'post_date_gmt' => gmdate( 'Y-m-d H:i:s', $product->get_date_created( 'edit' )->getTimestamp() ),
+ 'post_name' => $product->get_slug( 'edit' ),
+ )
+ ),
+ true
+ );
+
+ if ( $id && ! is_wp_error( $id ) ) {
+ $product->set_id( $id );
+
+ $this->update_post_meta( $product, true );
+ $this->update_terms( $product, true );
+ $this->update_visibility( $product, true );
+ $this->update_attributes( $product, true );
+ $this->update_version_and_type( $product );
+ $this->handle_updated_props( $product );
+ $this->clear_caches( $product );
+
+ $product->save_meta_data();
+ $product->apply_changes();
+
+ do_action( 'woocommerce_new_product', $id, $product );
+ }
+ }
+
+ /**
+ * Method to read a product from the database.
+ *
+ * @param WC_Product $product Product object.
+ * @throws Exception If invalid product.
+ */
+ public function read( &$product ) {
+ $product->set_defaults();
+ $post_object = get_post( $product->get_id() );
+
+ if ( ! $product->get_id() || ! $post_object || 'product' !== $post_object->post_type ) {
+ throw new Exception( __( 'Invalid product.', 'woocommerce' ) );
+ }
+
+ $product->set_props(
+ array(
+ 'name' => $post_object->post_title,
+ 'slug' => $post_object->post_name,
+ 'date_created' => $this->string_to_timestamp( $post_object->post_date_gmt ),
+ 'date_modified' => $this->string_to_timestamp( $post_object->post_modified_gmt ),
+ 'status' => $post_object->post_status,
+ 'description' => $post_object->post_content,
+ 'short_description' => $post_object->post_excerpt,
+ 'parent_id' => $post_object->post_parent,
+ 'menu_order' => $post_object->menu_order,
+ 'post_password' => $post_object->post_password,
+ 'reviews_allowed' => 'open' === $post_object->comment_status,
+ )
+ );
+
+ $this->read_attributes( $product );
+ $this->read_downloads( $product );
+ $this->read_visibility( $product );
+ $this->read_product_data( $product );
+ $this->read_extra_data( $product );
+ $product->set_object_read( true );
+
+ do_action( 'woocommerce_product_read', $product->get_id() );
+ }
+
+ /**
+ * Method to update a product in the database.
+ *
+ * @param WC_Product $product Product object.
+ */
+ public function update( &$product ) {
+ $product->save_meta_data();
+ $changes = $product->get_changes();
+
+ // Only update the post when the post data changes.
+ if ( array_intersect( array( 'description', 'short_description', 'name', 'parent_id', 'reviews_allowed', 'status', 'menu_order', 'date_created', 'date_modified', 'slug' ), array_keys( $changes ) ) ) {
+ $post_data = array(
+ 'post_content' => $product->get_description( 'edit' ),
+ 'post_excerpt' => $product->get_short_description( 'edit' ),
+ 'post_title' => $product->get_name( 'edit' ),
+ 'post_parent' => $product->get_parent_id( 'edit' ),
+ 'comment_status' => $product->get_reviews_allowed( 'edit' ) ? 'open' : 'closed',
+ 'post_status' => $product->get_status( 'edit' ) ? $product->get_status( 'edit' ) : 'publish',
+ 'menu_order' => $product->get_menu_order( 'edit' ),
+ 'post_password' => $product->get_post_password( 'edit' ),
+ 'post_name' => $product->get_slug( 'edit' ),
+ 'post_type' => 'product',
+ );
+ if ( $product->get_date_created( 'edit' ) ) {
+ $post_data['post_date'] = gmdate( 'Y-m-d H:i:s', $product->get_date_created( 'edit' )->getOffsetTimestamp() );
+ $post_data['post_date_gmt'] = gmdate( 'Y-m-d H:i:s', $product->get_date_created( 'edit' )->getTimestamp() );
+ }
+ if ( isset( $changes['date_modified'] ) && $product->get_date_modified( 'edit' ) ) {
+ $post_data['post_modified'] = gmdate( 'Y-m-d H:i:s', $product->get_date_modified( 'edit' )->getOffsetTimestamp() );
+ $post_data['post_modified_gmt'] = gmdate( 'Y-m-d H:i:s', $product->get_date_modified( 'edit' )->getTimestamp() );
+ } else {
+ $post_data['post_modified'] = current_time( 'mysql' );
+ $post_data['post_modified_gmt'] = current_time( 'mysql', 1 );
+ }
+
+ /**
+ * When updating this object, to prevent infinite loops, use $wpdb
+ * to update data, since wp_update_post spawns more calls to the
+ * save_post action.
+ *
+ * This ensures hooks are fired by either WP itself (admin screen save),
+ * or an update purely from CRUD.
+ */
+ if ( doing_action( 'save_post' ) ) {
+ $GLOBALS['wpdb']->update( $GLOBALS['wpdb']->posts, $post_data, array( 'ID' => $product->get_id() ) );
+ clean_post_cache( $product->get_id() );
+ } else {
+ wp_update_post( array_merge( array( 'ID' => $product->get_id() ), $post_data ) );
+ }
+ $product->read_meta_data( true ); // Refresh internal meta data, in case things were hooked into `save_post` or another WP hook.
+
+ } else { // Only update post modified time to record this save event.
+ $GLOBALS['wpdb']->update(
+ $GLOBALS['wpdb']->posts,
+ array(
+ 'post_modified' => current_time( 'mysql' ),
+ 'post_modified_gmt' => current_time( 'mysql', 1 ),
+ ),
+ array(
+ 'ID' => $product->get_id(),
+ )
+ );
+ clean_post_cache( $product->get_id() );
+ }
+
+ $this->update_post_meta( $product );
+ $this->update_terms( $product );
+ $this->update_visibility( $product );
+ $this->update_attributes( $product );
+ $this->update_version_and_type( $product );
+ $this->handle_updated_props( $product );
+ $this->clear_caches( $product );
+
+ $product->apply_changes();
+
+ do_action( 'woocommerce_update_product', $product->get_id(), $product );
+ }
+
+ /**
+ * Method to delete a product from the database.
+ *
+ * @param WC_Product $product Product object.
+ * @param array $args Array of args to pass to the delete method.
+ */
+ public function delete( &$product, $args = array() ) {
+ $id = $product->get_id();
+ $post_type = $product->is_type( 'variation' ) ? 'product_variation' : 'product';
+
+ $args = wp_parse_args(
+ $args,
+ array(
+ 'force_delete' => false,
+ )
+ );
+
+ if ( ! $id ) {
+ return;
+ }
+
+ if ( $args['force_delete'] ) {
+ do_action( 'woocommerce_before_delete_' . $post_type, $id );
+ wp_delete_post( $id );
+ $product->set_id( 0 );
+ do_action( 'woocommerce_delete_' . $post_type, $id );
+ } else {
+ wp_trash_post( $id );
+ $product->set_status( 'trash' );
+ do_action( 'woocommerce_trash_' . $post_type, $id );
+ }
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Additional Methods
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Read product data. Can be overridden by child classes to load other props.
+ *
+ * @param WC_Product $product Product object.
+ * @since 3.0.0
+ */
+ protected function read_product_data( &$product ) {
+ $id = $product->get_id();
+ $post_meta_values = get_post_meta( $id );
+ $meta_key_to_props = array(
+ '_sku' => 'sku',
+ '_regular_price' => 'regular_price',
+ '_sale_price' => 'sale_price',
+ '_price' => 'price',
+ '_sale_price_dates_from' => 'date_on_sale_from',
+ '_sale_price_dates_to' => 'date_on_sale_to',
+ 'total_sales' => 'total_sales',
+ '_tax_status' => 'tax_status',
+ '_tax_class' => 'tax_class',
+ '_manage_stock' => 'manage_stock',
+ '_backorders' => 'backorders',
+ '_low_stock_amount' => 'low_stock_amount',
+ '_sold_individually' => 'sold_individually',
+ '_weight' => 'weight',
+ '_length' => 'length',
+ '_width' => 'width',
+ '_height' => 'height',
+ '_upsell_ids' => 'upsell_ids',
+ '_crosssell_ids' => 'cross_sell_ids',
+ '_purchase_note' => 'purchase_note',
+ '_default_attributes' => 'default_attributes',
+ '_virtual' => 'virtual',
+ '_downloadable' => 'downloadable',
+ '_download_limit' => 'download_limit',
+ '_download_expiry' => 'download_expiry',
+ '_thumbnail_id' => 'image_id',
+ '_stock' => 'stock_quantity',
+ '_stock_status' => 'stock_status',
+ '_wc_average_rating' => 'average_rating',
+ '_wc_rating_count' => 'rating_counts',
+ '_wc_review_count' => 'review_count',
+ '_product_image_gallery' => 'gallery_image_ids',
+ );
+
+ $set_props = array();
+
+ foreach ( $meta_key_to_props as $meta_key => $prop ) {
+ $meta_value = isset( $post_meta_values[ $meta_key ][0] ) ? $post_meta_values[ $meta_key ][0] : null;
+ $set_props[ $prop ] = maybe_unserialize( $meta_value ); // get_post_meta only unserializes single values.
+ }
+
+ $set_props['category_ids'] = $this->get_term_ids( $product, 'product_cat' );
+ $set_props['tag_ids'] = $this->get_term_ids( $product, 'product_tag' );
+ $set_props['shipping_class_id'] = current( $this->get_term_ids( $product, 'product_shipping_class' ) );
+ $set_props['gallery_image_ids'] = array_filter( explode( ',', $set_props['gallery_image_ids'] ) );
+
+ $product->set_props( $set_props );
+ }
+
+ /**
+ * Re-reads stock from the DB ignoring changes.
+ *
+ * @param WC_Product $product Product object.
+ * @param int|float $new_stock New stock level if already read.
+ */
+ public function read_stock_quantity( &$product, $new_stock = null ) {
+ $object_read = $product->get_object_read();
+ $product->set_object_read( false ); // This makes update of qty go directly to data- instead of changes-array of the product object (which is needed as the data should hold status of the object as it was read from the db).
+ $product->set_stock_quantity( is_null( $new_stock ) ? get_post_meta( $product->get_id(), '_stock', true ) : $new_stock );
+ $product->set_object_read( $object_read );
+ }
+
+ /**
+ * Read extra data associated with the product, like button text or product URL for external products.
+ *
+ * @param WC_Product $product Product object.
+ * @since 3.0.0
+ */
+ protected function read_extra_data( &$product ) {
+ foreach ( $product->get_extra_data_keys() as $key ) {
+ $function = 'set_' . $key;
+ if ( is_callable( array( $product, $function ) ) ) {
+ $product->{$function}( get_post_meta( $product->get_id(), '_' . $key, true ) );
+ }
+ }
+ }
+
+ /**
+ * Convert visibility terms to props.
+ * Catalog visibility valid values are 'visible', 'catalog', 'search', and 'hidden'.
+ *
+ * @param WC_Product $product Product object.
+ * @since 3.0.0
+ */
+ protected function read_visibility( &$product ) {
+ $terms = get_the_terms( $product->get_id(), 'product_visibility' );
+ $term_names = is_array( $terms ) ? wp_list_pluck( $terms, 'name' ) : array();
+ $featured = in_array( 'featured', $term_names, true );
+ $exclude_search = in_array( 'exclude-from-search', $term_names, true );
+ $exclude_catalog = in_array( 'exclude-from-catalog', $term_names, true );
+
+ if ( $exclude_search && $exclude_catalog ) {
+ $catalog_visibility = 'hidden';
+ } elseif ( $exclude_search ) {
+ $catalog_visibility = 'catalog';
+ } elseif ( $exclude_catalog ) {
+ $catalog_visibility = 'search';
+ } else {
+ $catalog_visibility = 'visible';
+ }
+
+ $product->set_props(
+ array(
+ 'featured' => $featured,
+ 'catalog_visibility' => $catalog_visibility,
+ )
+ );
+ }
+
+ /**
+ * Read attributes from post meta.
+ *
+ * @param WC_Product $product Product object.
+ */
+ protected function read_attributes( &$product ) {
+ $meta_attributes = get_post_meta( $product->get_id(), '_product_attributes', true );
+
+ if ( ! empty( $meta_attributes ) && is_array( $meta_attributes ) ) {
+ $attributes = array();
+ foreach ( $meta_attributes as $meta_attribute_key => $meta_attribute_value ) {
+ $meta_value = array_merge(
+ array(
+ 'name' => '',
+ 'value' => '',
+ 'position' => 0,
+ 'is_visible' => 0,
+ 'is_variation' => 0,
+ 'is_taxonomy' => 0,
+ ),
+ (array) $meta_attribute_value
+ );
+
+ // Check if is a taxonomy attribute.
+ if ( ! empty( $meta_value['is_taxonomy'] ) ) {
+ if ( ! taxonomy_exists( $meta_value['name'] ) ) {
+ continue;
+ }
+ $id = wc_attribute_taxonomy_id_by_name( $meta_value['name'] );
+ $options = wc_get_object_terms( $product->get_id(), $meta_value['name'], 'term_id' );
+ } else {
+ $id = 0;
+ $options = wc_get_text_attributes( $meta_value['value'] );
+ }
+
+ $attribute = new WC_Product_Attribute();
+ $attribute->set_id( $id );
+ $attribute->set_name( $meta_value['name'] );
+ $attribute->set_options( $options );
+ $attribute->set_position( $meta_value['position'] );
+ $attribute->set_visible( $meta_value['is_visible'] );
+ $attribute->set_variation( $meta_value['is_variation'] );
+ $attributes[] = $attribute;
+ }
+ $product->set_attributes( $attributes );
+ }
+ }
+
+ /**
+ * Read downloads from post meta.
+ *
+ * @param WC_Product $product Product object.
+ * @since 3.0.0
+ */
+ protected function read_downloads( &$product ) {
+ $meta_values = array_filter( (array) get_post_meta( $product->get_id(), '_downloadable_files', true ) );
+
+ if ( $meta_values ) {
+ $downloads = array();
+ foreach ( $meta_values as $key => $value ) {
+ if ( ! isset( $value['name'], $value['file'] ) ) {
+ continue;
+ }
+ $download = new WC_Product_Download();
+ $download->set_id( $key );
+ $download->set_name( $value['name'] ? $value['name'] : wc_get_filename_from_url( $value['file'] ) );
+ $download->set_file( apply_filters( 'woocommerce_file_download_path', $value['file'], $product, $key ) );
+ $downloads[] = $download;
+ }
+ $product->set_downloads( $downloads );
+ }
+ }
+
+ /**
+ * Helper method that updates all the post meta for a product based on it's settings in the WC_Product class.
+ *
+ * @param WC_Product $product Product object.
+ * @param bool $force Force update. Used during create.
+ * @since 3.0.0
+ */
+ protected function update_post_meta( &$product, $force = false ) {
+ $meta_key_to_props = array(
+ '_sku' => 'sku',
+ '_regular_price' => 'regular_price',
+ '_sale_price' => 'sale_price',
+ '_sale_price_dates_from' => 'date_on_sale_from',
+ '_sale_price_dates_to' => 'date_on_sale_to',
+ 'total_sales' => 'total_sales',
+ '_tax_status' => 'tax_status',
+ '_tax_class' => 'tax_class',
+ '_manage_stock' => 'manage_stock',
+ '_backorders' => 'backorders',
+ '_low_stock_amount' => 'low_stock_amount',
+ '_sold_individually' => 'sold_individually',
+ '_weight' => 'weight',
+ '_length' => 'length',
+ '_width' => 'width',
+ '_height' => 'height',
+ '_upsell_ids' => 'upsell_ids',
+ '_crosssell_ids' => 'cross_sell_ids',
+ '_purchase_note' => 'purchase_note',
+ '_default_attributes' => 'default_attributes',
+ '_virtual' => 'virtual',
+ '_downloadable' => 'downloadable',
+ '_product_image_gallery' => 'gallery_image_ids',
+ '_download_limit' => 'download_limit',
+ '_download_expiry' => 'download_expiry',
+ '_thumbnail_id' => 'image_id',
+ '_stock' => 'stock_quantity',
+ '_stock_status' => 'stock_status',
+ '_wc_average_rating' => 'average_rating',
+ '_wc_rating_count' => 'rating_counts',
+ '_wc_review_count' => 'review_count',
+ );
+
+ // Make sure to take extra data (like product url or text for external products) into account.
+ $extra_data_keys = $product->get_extra_data_keys();
+
+ foreach ( $extra_data_keys as $key ) {
+ $meta_key_to_props[ '_' . $key ] = $key;
+ }
+
+ $props_to_update = $force ? $meta_key_to_props : $this->get_props_to_update( $product, $meta_key_to_props );
+
+ foreach ( $props_to_update as $meta_key => $prop ) {
+ $value = $product->{"get_$prop"}( 'edit' );
+ $value = is_string( $value ) ? wp_slash( $value ) : $value;
+ switch ( $prop ) {
+ case 'virtual':
+ case 'downloadable':
+ case 'manage_stock':
+ case 'sold_individually':
+ $value = wc_bool_to_string( $value );
+ break;
+ case 'gallery_image_ids':
+ $value = implode( ',', $value );
+ break;
+ case 'date_on_sale_from':
+ case 'date_on_sale_to':
+ $value = $value ? $value->getTimestamp() : '';
+ break;
+ }
+
+ $updated = $this->update_or_delete_post_meta( $product, $meta_key, $value );
+
+ if ( $updated ) {
+ $this->updated_props[] = $prop;
+ }
+ }
+
+ // Update extra data associated with the product like button text or product URL for external products.
+ if ( ! $this->extra_data_saved ) {
+ foreach ( $extra_data_keys as $key ) {
+ $meta_key = '_' . $key;
+ $function = 'get_' . $key;
+ if ( ! array_key_exists( $meta_key, $props_to_update ) ) {
+ continue;
+ }
+ if ( is_callable( array( $product, $function ) ) ) {
+ $value = $product->{$function}( 'edit' );
+ $value = is_string( $value ) ? wp_slash( $value ) : $value;
+ $updated = $this->update_or_delete_post_meta( $product, $meta_key, $value );
+
+ if ( $updated ) {
+ $this->updated_props[] = $key;
+ }
+ }
+ }
+ }
+
+ if ( $this->update_downloads( $product, $force ) ) {
+ $this->updated_props[] = 'downloads';
+ }
+ }
+
+ /**
+ * Handle updated meta props after updating meta data.
+ *
+ * @since 3.0.0
+ * @param WC_Product $product Product Object.
+ */
+ protected function handle_updated_props( &$product ) {
+ $price_is_synced = $product->is_type( array( 'variable', 'grouped' ) );
+
+ if ( ! $price_is_synced ) {
+ if ( in_array( 'regular_price', $this->updated_props, true ) || in_array( 'sale_price', $this->updated_props, true ) ) {
+ if ( $product->get_sale_price( 'edit' ) >= $product->get_regular_price( 'edit' ) ) {
+ update_post_meta( $product->get_id(), '_sale_price', '' );
+ $product->set_sale_price( '' );
+ }
+ }
+
+ if ( in_array( 'date_on_sale_from', $this->updated_props, true ) || in_array( 'date_on_sale_to', $this->updated_props, true ) || in_array( 'regular_price', $this->updated_props, true ) || in_array( 'sale_price', $this->updated_props, true ) || in_array( 'product_type', $this->updated_props, true ) ) {
+ if ( $product->is_on_sale( 'edit' ) ) {
+ update_post_meta( $product->get_id(), '_price', $product->get_sale_price( 'edit' ) );
+ $product->set_price( $product->get_sale_price( 'edit' ) );
+ } else {
+ update_post_meta( $product->get_id(), '_price', $product->get_regular_price( 'edit' ) );
+ $product->set_price( $product->get_regular_price( 'edit' ) );
+ }
+ }
+ }
+
+ if ( in_array( 'stock_quantity', $this->updated_props, true ) ) {
+ if ( $product->is_type( 'variation' ) ) {
+ do_action( 'woocommerce_variation_set_stock', $product );
+ } else {
+ do_action( 'woocommerce_product_set_stock', $product );
+ }
+ }
+
+ if ( in_array( 'stock_status', $this->updated_props, true ) ) {
+ if ( $product->is_type( 'variation' ) ) {
+ do_action( 'woocommerce_variation_set_stock_status', $product->get_id(), $product->get_stock_status(), $product );
+ } else {
+ do_action( 'woocommerce_product_set_stock_status', $product->get_id(), $product->get_stock_status(), $product );
+ }
+ }
+
+ if ( array_intersect( $this->updated_props, array( 'sku', 'regular_price', 'sale_price', 'date_on_sale_from', 'date_on_sale_to', 'total_sales', 'average_rating', 'stock_quantity', 'stock_status', 'manage_stock', 'downloadable', 'virtual', 'tax_status', 'tax_class' ) ) ) {
+ $this->update_lookup_table( $product->get_id(), 'wc_product_meta_lookup' );
+ }
+
+ // Trigger action so 3rd parties can deal with updated props.
+ do_action( 'woocommerce_product_object_updated_props', $product, $this->updated_props );
+
+ // After handling, we can reset the props array.
+ $this->updated_props = array();
+ }
+
+ /**
+ * For all stored terms in all taxonomies, save them to the DB.
+ *
+ * @param WC_Product $product Product object.
+ * @param bool $force Force update. Used during create.
+ * @since 3.0.0
+ */
+ protected function update_terms( &$product, $force = false ) {
+ $changes = $product->get_changes();
+
+ if ( $force || array_key_exists( 'category_ids', $changes ) ) {
+ $categories = $product->get_category_ids( 'edit' );
+
+ if ( empty( $categories ) && get_option( 'default_product_cat', 0 ) ) {
+ $categories = array( get_option( 'default_product_cat', 0 ) );
+ }
+
+ wp_set_post_terms( $product->get_id(), $categories, 'product_cat', false );
+ }
+ if ( $force || array_key_exists( 'tag_ids', $changes ) ) {
+ wp_set_post_terms( $product->get_id(), $product->get_tag_ids( 'edit' ), 'product_tag', false );
+ }
+ if ( $force || array_key_exists( 'shipping_class_id', $changes ) ) {
+ wp_set_post_terms( $product->get_id(), array( $product->get_shipping_class_id( 'edit' ) ), 'product_shipping_class', false );
+ }
+ }
+
+ /**
+ * Update visibility terms based on props.
+ *
+ * @since 3.0.0
+ *
+ * @param WC_Product $product Product object.
+ * @param bool $force Force update. Used during create.
+ */
+ protected function update_visibility( &$product, $force = false ) {
+ $changes = $product->get_changes();
+
+ if ( $force || array_intersect( array( 'featured', 'stock_status', 'average_rating', 'catalog_visibility' ), array_keys( $changes ) ) ) {
+ $terms = array();
+
+ if ( $product->get_featured() ) {
+ $terms[] = 'featured';
+ }
+
+ if ( 'outofstock' === $product->get_stock_status() ) {
+ $terms[] = 'outofstock';
+ }
+
+ $rating = min( 5, NumberUtil::round( $product->get_average_rating(), 0 ) );
+
+ if ( $rating > 0 ) {
+ $terms[] = 'rated-' . $rating;
+ }
+
+ switch ( $product->get_catalog_visibility() ) {
+ case 'hidden':
+ $terms[] = 'exclude-from-search';
+ $terms[] = 'exclude-from-catalog';
+ break;
+ case 'catalog':
+ $terms[] = 'exclude-from-search';
+ break;
+ case 'search':
+ $terms[] = 'exclude-from-catalog';
+ break;
+ }
+
+ if ( ! is_wp_error( wp_set_post_terms( $product->get_id(), $terms, 'product_visibility', false ) ) ) {
+ do_action( 'woocommerce_product_set_visibility', $product->get_id(), $product->get_catalog_visibility() );
+ }
+ }
+ }
+
+ /**
+ * Update attributes which are a mix of terms and meta data.
+ *
+ * @param WC_Product $product Product object.
+ * @param bool $force Force update. Used during create.
+ * @since 3.0.0
+ */
+ protected function update_attributes( &$product, $force = false ) {
+ $changes = $product->get_changes();
+
+ if ( $force || array_key_exists( 'attributes', $changes ) ) {
+ $attributes = $product->get_attributes();
+ $meta_values = array();
+
+ if ( $attributes ) {
+ foreach ( $attributes as $attribute_key => $attribute ) {
+ $value = '';
+
+ if ( is_null( $attribute ) ) {
+ if ( taxonomy_exists( $attribute_key ) ) {
+ // Handle attributes that have been unset.
+ wp_set_object_terms( $product->get_id(), array(), $attribute_key );
+ } elseif ( taxonomy_exists( urldecode( $attribute_key ) ) ) {
+ // Handle attributes that have been unset.
+ wp_set_object_terms( $product->get_id(), array(), urldecode( $attribute_key ) );
+ }
+ continue;
+
+ } elseif ( $attribute->is_taxonomy() ) {
+ wp_set_object_terms( $product->get_id(), wp_list_pluck( (array) $attribute->get_terms(), 'term_id' ), $attribute->get_name() );
+ } else {
+ $value = wc_implode_text_attributes( $attribute->get_options() );
+ }
+
+ // Store in format WC uses in meta.
+ $meta_values[ $attribute_key ] = array(
+ 'name' => $attribute->get_name(),
+ 'value' => $value,
+ 'position' => $attribute->get_position(),
+ 'is_visible' => $attribute->get_visible() ? 1 : 0,
+ 'is_variation' => $attribute->get_variation() ? 1 : 0,
+ 'is_taxonomy' => $attribute->is_taxonomy() ? 1 : 0,
+ );
+ }
+ }
+ // Note, we use wp_slash to add extra level of escaping. See https://codex.wordpress.org/Function_Reference/update_post_meta#Workaround.
+ $this->update_or_delete_post_meta( $product, '_product_attributes', wp_slash( $meta_values ) );
+ }
+ }
+
+ /**
+ * Update downloads.
+ *
+ * @since 3.0.0
+ * @param WC_Product $product Product object.
+ * @param bool $force Force update. Used during create.
+ * @return bool If updated or not.
+ */
+ protected function update_downloads( &$product, $force = false ) {
+ $changes = $product->get_changes();
+
+ if ( $force || array_key_exists( 'downloads', $changes ) ) {
+ $downloads = $product->get_downloads();
+ $meta_values = array();
+
+ if ( $downloads ) {
+ foreach ( $downloads as $key => $download ) {
+ // Store in format WC uses in meta.
+ $meta_values[ $key ] = $download->get_data();
+ }
+ }
+
+ if ( $product->is_type( 'variation' ) ) {
+ do_action( 'woocommerce_process_product_file_download_paths', $product->get_parent_id(), $product->get_id(), $downloads );
+ } else {
+ do_action( 'woocommerce_process_product_file_download_paths', $product->get_id(), 0, $downloads );
+ }
+
+ return $this->update_or_delete_post_meta( $product, '_downloadable_files', wp_slash( $meta_values ) );
+ }
+ return false;
+ }
+
+ /**
+ * Make sure we store the product type and version (to track data changes).
+ *
+ * @param WC_Product $product Product object.
+ * @since 3.0.0
+ */
+ protected function update_version_and_type( &$product ) {
+ $old_type = WC_Product_Factory::get_product_type( $product->get_id() );
+ $new_type = $product->get_type();
+
+ wp_set_object_terms( $product->get_id(), $new_type, 'product_type' );
+ update_post_meta( $product->get_id(), '_product_version', Constants::get_constant( 'WC_VERSION' ) );
+
+ // Action for the transition.
+ if ( $old_type !== $new_type ) {
+ $this->updated_props[] = 'product_type';
+ do_action( 'woocommerce_product_type_changed', $product, $old_type, $new_type );
+ }
+ }
+
+ /**
+ * Clear any caches.
+ *
+ * @param WC_Product $product Product object.
+ * @since 3.0.0
+ */
+ protected function clear_caches( &$product ) {
+ wc_delete_product_transients( $product->get_id() );
+ if ( $product->get_parent_id( 'edit' ) ) {
+ wc_delete_product_transients( $product->get_parent_id( 'edit' ) );
+ WC_Cache_Helper::invalidate_cache_group( 'product_' . $product->get_parent_id( 'edit' ) );
+ }
+ WC_Cache_Helper::invalidate_attribute_count( array_keys( $product->get_attributes() ) );
+ WC_Cache_Helper::invalidate_cache_group( 'product_' . $product->get_id() );
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | wc-product-functions.php methods
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Returns an array of on sale products, as an array of objects with an
+ * ID and parent_id present. Example: $return[0]->id, $return[0]->parent_id.
+ *
+ * @return array
+ * @since 3.0.0
+ */
+ public function get_on_sale_products() {
+ global $wpdb;
+
+ $exclude_term_ids = array();
+ $outofstock_join = '';
+ $outofstock_where = '';
+ $non_published_where = '';
+ $product_visibility_term_ids = wc_get_product_visibility_term_ids();
+
+ if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) && $product_visibility_term_ids['outofstock'] ) {
+ $exclude_term_ids[] = $product_visibility_term_ids['outofstock'];
+ }
+
+ if ( count( $exclude_term_ids ) ) {
+ $outofstock_join = " LEFT JOIN ( SELECT object_id FROM {$wpdb->term_relationships} WHERE term_taxonomy_id IN ( " . implode( ',', array_map( 'absint', $exclude_term_ids ) ) . ' ) ) AS exclude_join ON exclude_join.object_id = id';
+ $outofstock_where = ' AND exclude_join.object_id IS NULL';
+ }
+
+ // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
+ return $wpdb->get_results(
+ "
+ SELECT posts.ID as id, posts.post_parent as parent_id
+ FROM {$wpdb->posts} AS posts
+ INNER JOIN {$wpdb->wc_product_meta_lookup} AS lookup ON posts.ID = lookup.product_id
+ $outofstock_join
+ WHERE posts.post_type IN ( 'product', 'product_variation' )
+ AND posts.post_status = 'publish'
+ AND lookup.onsale = 1
+ $outofstock_where
+ AND posts.post_parent NOT IN (
+ SELECT ID FROM `$wpdb->posts` as posts
+ WHERE posts.post_type = 'product'
+ AND posts.post_parent = 0
+ AND posts.post_status != 'publish'
+ )
+ GROUP BY posts.ID
+ "
+ );
+ // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
+ }
+
+ /**
+ * Returns a list of product IDs ( id as key => parent as value) that are
+ * featured. Uses get_posts instead of wc_get_products since we want
+ * some extra meta queries and ALL products (posts_per_page = -1).
+ *
+ * @return array
+ * @since 3.0.0
+ */
+ public function get_featured_product_ids() {
+ $product_visibility_term_ids = wc_get_product_visibility_term_ids();
+
+ return get_posts(
+ array(
+ 'post_type' => array( 'product', 'product_variation' ),
+ 'posts_per_page' => -1,
+ 'post_status' => 'publish',
+ 'tax_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
+ 'relation' => 'AND',
+ array(
+ 'taxonomy' => 'product_visibility',
+ 'field' => 'term_taxonomy_id',
+ 'terms' => array( $product_visibility_term_ids['featured'] ),
+ ),
+ array(
+ 'taxonomy' => 'product_visibility',
+ 'field' => 'term_taxonomy_id',
+ 'terms' => array( $product_visibility_term_ids['exclude-from-catalog'] ),
+ 'operator' => 'NOT IN',
+ ),
+ ),
+ 'fields' => 'id=>parent',
+ )
+ );
+ }
+
+ /**
+ * Check if product sku is found for any other product IDs.
+ *
+ * @since 3.0.0
+ * @param int $product_id Product ID.
+ * @param string $sku Will be slashed to work around https://core.trac.wordpress.org/ticket/27421.
+ * @return bool
+ */
+ public function is_existing_sku( $product_id, $sku ) {
+ global $wpdb;
+
+ // phpcs:ignore WordPress.VIP.DirectDatabaseQuery.DirectQuery
+ return (bool) $wpdb->get_var(
+ $wpdb->prepare(
+ "
+ SELECT posts.ID
+ FROM {$wpdb->posts} as posts
+ INNER JOIN {$wpdb->wc_product_meta_lookup} AS lookup ON posts.ID = lookup.product_id
+ WHERE
+ posts.post_type IN ( 'product', 'product_variation' )
+ AND posts.post_status != 'trash'
+ AND lookup.sku = %s
+ AND lookup.product_id <> %d
+ LIMIT 1
+ ",
+ wp_slash( $sku ),
+ $product_id
+ )
+ );
+ }
+
+ /**
+ * Return product ID based on SKU.
+ *
+ * @since 3.0.0
+ * @param string $sku Product SKU.
+ * @return int
+ */
+ public function get_product_id_by_sku( $sku ) {
+ global $wpdb;
+
+ // phpcs:ignore WordPress.VIP.DirectDatabaseQuery.DirectQuery
+ $id = $wpdb->get_var(
+ $wpdb->prepare(
+ "
+ SELECT posts.ID
+ FROM {$wpdb->posts} as posts
+ INNER JOIN {$wpdb->wc_product_meta_lookup} AS lookup ON posts.ID = lookup.product_id
+ WHERE
+ posts.post_type IN ( 'product', 'product_variation' )
+ AND posts.post_status != 'trash'
+ AND lookup.sku = %s
+ LIMIT 1
+ ",
+ $sku
+ )
+ );
+
+ return (int) apply_filters( 'woocommerce_get_product_id_by_sku', $id, $sku );
+ }
+
+ /**
+ * Returns an array of IDs of products that have sales starting soon.
+ *
+ * @since 3.0.0
+ * @return array
+ */
+ public function get_starting_sales() {
+ global $wpdb;
+
+ // phpcs:ignore WordPress.VIP.DirectDatabaseQuery.DirectQuery
+ return $wpdb->get_col(
+ $wpdb->prepare(
+ "SELECT postmeta.post_id FROM {$wpdb->postmeta} as postmeta
+ LEFT JOIN {$wpdb->postmeta} as postmeta_2 ON postmeta.post_id = postmeta_2.post_id
+ LEFT JOIN {$wpdb->postmeta} as postmeta_3 ON postmeta.post_id = postmeta_3.post_id
+ WHERE postmeta.meta_key = '_sale_price_dates_from'
+ AND postmeta_2.meta_key = '_price'
+ AND postmeta_3.meta_key = '_sale_price'
+ AND postmeta.meta_value > 0
+ AND postmeta.meta_value < %s
+ AND postmeta_2.meta_value != postmeta_3.meta_value",
+ time()
+ )
+ );
+ }
+
+ /**
+ * Returns an array of IDs of products that have sales which are due to end.
+ *
+ * @since 3.0.0
+ * @return array
+ */
+ public function get_ending_sales() {
+ global $wpdb;
+
+ // phpcs:ignore WordPress.VIP.DirectDatabaseQuery.DirectQuery
+ return $wpdb->get_col(
+ $wpdb->prepare(
+ "SELECT postmeta.post_id FROM {$wpdb->postmeta} as postmeta
+ LEFT JOIN {$wpdb->postmeta} as postmeta_2 ON postmeta.post_id = postmeta_2.post_id
+ LEFT JOIN {$wpdb->postmeta} as postmeta_3 ON postmeta.post_id = postmeta_3.post_id
+ WHERE postmeta.meta_key = '_sale_price_dates_to'
+ AND postmeta_2.meta_key = '_price'
+ AND postmeta_3.meta_key = '_regular_price'
+ AND postmeta.meta_value > 0
+ AND postmeta.meta_value < %s
+ AND postmeta_2.meta_value != postmeta_3.meta_value",
+ time()
+ )
+ );
+ }
+
+ /**
+ * Find a matching (enabled) variation within a variable product.
+ *
+ * @since 3.0.0
+ * @param WC_Product $product Variable product.
+ * @param array $match_attributes Array of attributes we want to try to match.
+ * @return int Matching variation ID or 0.
+ */
+ public function find_matching_product_variation( $product, $match_attributes = array() ) {
+ global $wpdb;
+
+ $meta_attribute_names = array();
+
+ // Get attributes to match in meta.
+ foreach ( $product->get_attributes() as $attribute ) {
+ if ( ! $attribute->get_variation() ) {
+ continue;
+ }
+ $meta_attribute_names[] = 'attribute_' . sanitize_title( $attribute->get_name() );
+ }
+
+ // Get the attributes of the variations.
+ $query = $wpdb->prepare(
+ "
+ SELECT postmeta.post_id, postmeta.meta_key, postmeta.meta_value, posts.menu_order FROM {$wpdb->postmeta} as postmeta
+ LEFT JOIN {$wpdb->posts} as posts ON postmeta.post_id=posts.ID
+ WHERE postmeta.post_id IN (
+ SELECT ID FROM {$wpdb->posts}
+ WHERE {$wpdb->posts}.post_parent = %d
+ AND {$wpdb->posts}.post_status = 'publish'
+ AND {$wpdb->posts}.post_type = 'product_variation'
+ )
+ ",
+ $product->get_id()
+ );
+
+ $query .= ' AND postmeta.meta_key IN ( "' . implode( '","', array_map( 'esc_sql', $meta_attribute_names ) ) . '" )';
+
+ $query .= ' ORDER BY posts.menu_order ASC, postmeta.post_id ASC;';
+
+ $attributes = $wpdb->get_results( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
+
+ if ( ! $attributes ) {
+ return 0;
+ }
+
+ $sorted_meta = array();
+
+ foreach ( $attributes as $m ) {
+ $sorted_meta[ $m->post_id ][ $m->meta_key ] = $m->meta_value; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
+ }
+
+ /**
+ * Check each variation to find the one that matches the $match_attributes.
+ *
+ * Note: Not all meta fields will be set which is why we check existance.
+ */
+ foreach ( $sorted_meta as $variation_id => $variation ) {
+ $match = true;
+
+ // Loop over the variation meta keys and values i.e. what is saved to the products. Note: $attribute_value is empty when 'any' is in use.
+ foreach ( $variation as $attribute_key => $attribute_value ) {
+ $match_any_value = '' === $attribute_value;
+
+ if ( ! $match_any_value && ! array_key_exists( $attribute_key, $match_attributes ) ) {
+ $match = false; // Requires a selection but no value was provide.
+ }
+
+ if ( array_key_exists( $attribute_key, $match_attributes ) ) { // Value to match was provided.
+ if ( ! $match_any_value && $match_attributes[ $attribute_key ] !== $attribute_value ) {
+ $match = false; // Provided value does not match variation.
+ }
+ }
+ }
+
+ if ( true === $match ) {
+ return $variation_id;
+ }
+ }
+
+ if ( version_compare( get_post_meta( $product->get_id(), '_product_version', true ), '2.4.0', '<' ) ) {
+ /**
+ * Pre 2.4 handling where 'slugs' were saved instead of the full text attribute.
+ * Fallback is here because there are cases where data will be 'synced' but the product version will remain the same.
+ */
+ return ( array_map( 'sanitize_title', $match_attributes ) === $match_attributes ) ? 0 : $this->find_matching_product_variation( $product, array_map( 'sanitize_title', $match_attributes ) );
+ }
+
+ return 0;
+ }
+
+ /**
+ * Creates all possible combinations of variations from the attributes, without creating duplicates.
+ *
+ * @since 3.6.0
+ * @todo Add to interface in 4.0.
+ * @param WC_Product $product Variable product.
+ * @param int $limit Limit the number of created variations.
+ * @return int Number of created variations.
+ */
+ public function create_all_product_variations( $product, $limit = -1 ) {
+ $count = 0;
+
+ if ( ! $product ) {
+ return $count;
+ }
+
+ $attributes = wc_list_pluck( array_filter( $product->get_attributes(), 'wc_attributes_array_filter_variation' ), 'get_slugs' );
+
+ if ( empty( $attributes ) ) {
+ return $count;
+ }
+
+ // Get existing variations so we don't create duplicates.
+ $existing_variations = array_map( 'wc_get_product', $product->get_children() );
+ $existing_attributes = array();
+
+ foreach ( $existing_variations as $existing_variation ) {
+ $existing_attributes[] = $existing_variation->get_attributes();
+ }
+
+ $possible_attributes = array_reverse( wc_array_cartesian( $attributes ) );
+
+ foreach ( $possible_attributes as $possible_attribute ) {
+ // Allow any order if key/values -- do not use strict mode.
+ if ( in_array( $possible_attribute, $existing_attributes ) ) { // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
+ continue;
+ }
+ $variation = wc_get_product_object( 'variation' );
+ $variation->set_parent_id( $product->get_id() );
+ $variation->set_attributes( $possible_attribute );
+ $variation_id = $variation->save();
+
+ do_action( 'product_variation_linked', $variation_id );
+
+ $count ++;
+
+ if ( $limit > 0 && $count >= $limit ) {
+ break;
+ }
+ }
+
+ return $count;
+ }
+
+ /**
+ * Make sure all variations have a sort order set so they can be reordered correctly.
+ *
+ * @param int $parent_id Product ID.
+ */
+ public function sort_all_product_variations( $parent_id ) {
+ global $wpdb;
+
+ // phpcs:ignore WordPress.VIP.DirectDatabaseQuery.DirectQuery
+ $ids = $wpdb->get_col(
+ $wpdb->prepare(
+ "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'product_variation' AND post_parent = %d AND post_status = 'publish' ORDER BY menu_order ASC, ID ASC",
+ $parent_id
+ )
+ );
+ $index = 1;
+
+ foreach ( $ids as $id ) {
+ // phpcs:ignore WordPress.VIP.DirectDatabaseQuery.DirectQuery
+ $wpdb->update( $wpdb->posts, array( 'menu_order' => ( $index++ ) ), array( 'ID' => absint( $id ) ) );
+ }
+ }
+
+ /**
+ * Return a list of related products (using data like categories and IDs).
+ *
+ * @since 3.0.0
+ * @param array $cats_array List of categories IDs.
+ * @param array $tags_array List of tags IDs.
+ * @param array $exclude_ids Excluded IDs.
+ * @param int $limit Limit of results.
+ * @param int $product_id Product ID.
+ * @return array
+ */
+ public function get_related_products( $cats_array, $tags_array, $exclude_ids, $limit, $product_id ) {
+ global $wpdb;
+
+ $args = array(
+ 'categories' => $cats_array,
+ 'tags' => $tags_array,
+ 'exclude_ids' => $exclude_ids,
+ 'limit' => $limit + 10,
+ );
+
+ $related_product_query = (array) apply_filters( 'woocommerce_product_related_posts_query', $this->get_related_products_query( $cats_array, $tags_array, $exclude_ids, $limit + 10 ), $product_id, $args );
+
+ // phpcs:ignore WordPress.VIP.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.NotPrepared
+ return $wpdb->get_col( implode( ' ', $related_product_query ) );
+ }
+
+ /**
+ * Builds the related posts query.
+ *
+ * @since 3.0.0
+ *
+ * @param array $cats_array List of categories IDs.
+ * @param array $tags_array List of tags IDs.
+ * @param array $exclude_ids Excluded IDs.
+ * @param int $limit Limit of results.
+ *
+ * @return array
+ */
+ public function get_related_products_query( $cats_array, $tags_array, $exclude_ids, $limit ) {
+ global $wpdb;
+
+ $include_term_ids = array_merge( $cats_array, $tags_array );
+ $exclude_term_ids = array();
+ $product_visibility_term_ids = wc_get_product_visibility_term_ids();
+
+ if ( $product_visibility_term_ids['exclude-from-catalog'] ) {
+ $exclude_term_ids[] = $product_visibility_term_ids['exclude-from-catalog'];
+ }
+
+ if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) && $product_visibility_term_ids['outofstock'] ) {
+ $exclude_term_ids[] = $product_visibility_term_ids['outofstock'];
+ }
+
+ $query = array(
+ 'fields' => "
+ SELECT DISTINCT ID FROM {$wpdb->posts} p
+ ",
+ 'join' => '',
+ 'where' => "
+ WHERE 1=1
+ AND p.post_status = 'publish'
+ AND p.post_type = 'product'
+
+ ",
+ 'limits' => '
+ LIMIT ' . absint( $limit ) . '
+ ',
+ );
+
+ if ( count( $exclude_term_ids ) ) {
+ $query['join'] .= " LEFT JOIN ( SELECT object_id FROM {$wpdb->term_relationships} WHERE term_taxonomy_id IN ( " . implode( ',', array_map( 'absint', $exclude_term_ids ) ) . ' ) ) AS exclude_join ON exclude_join.object_id = p.ID';
+ $query['where'] .= ' AND exclude_join.object_id IS NULL';
+ }
+
+ if ( count( $include_term_ids ) ) {
+ $query['join'] .= " INNER JOIN ( SELECT object_id FROM {$wpdb->term_relationships} INNER JOIN {$wpdb->term_taxonomy} using( term_taxonomy_id ) WHERE term_id IN ( " . implode( ',', array_map( 'absint', $include_term_ids ) ) . ' ) ) AS include_join ON include_join.object_id = p.ID';
+ }
+
+ if ( count( $exclude_ids ) ) {
+ $query['where'] .= ' AND p.ID NOT IN ( ' . implode( ',', array_map( 'absint', $exclude_ids ) ) . ' )';
+ }
+
+ return $query;
+ }
+
+ /**
+ * Update a product's stock amount directly in the database.
+ *
+ * Updates both post meta and lookup tables. Ignores manage stock setting on the product.
+ *
+ * @param int $product_id_with_stock Product ID.
+ * @param int|float|null $stock_quantity Stock quantity.
+ */
+ protected function set_product_stock( $product_id_with_stock, $stock_quantity ) {
+ global $wpdb;
+
+ // Generate SQL.
+ $sql = $wpdb->prepare(
+ "UPDATE {$wpdb->postmeta} SET meta_value = %f WHERE post_id = %d AND meta_key='_stock'",
+ $stock_quantity,
+ $product_id_with_stock
+ );
+
+ $sql = apply_filters( 'woocommerce_update_product_stock_query', $sql, $product_id_with_stock, $stock_quantity, 'set' );
+
+ $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.NotPrepared
+
+ // Cache delete is required (not only) to set correct data for lookup table (which reads from cache).
+ // Sometimes I wonder if it shouldn't be part of update_lookup_table.
+ wp_cache_delete( $product_id_with_stock, 'post_meta' );
+
+ $this->update_lookup_table( $product_id_with_stock, 'wc_product_meta_lookup' );
+ }
+
+ /**
+ * Update a product's stock amount directly.
+ *
+ * Uses queries rather than update_post_meta so we can do this in one query (to avoid stock issues).
+ * Ignores manage stock setting on the product and sets quantities directly in the db: post meta and lookup tables.
+ * Uses locking to update the quantity. If the lock is not acquired, change is lost.
+ *
+ * @since 3.0.0 this supports set, increase and decrease.
+ * @param int $product_id_with_stock Product ID.
+ * @param int|float|null $stock_quantity Stock quantity.
+ * @param string $operation Set, increase and decrease.
+ * @return int|float New stock level.
+ */
+ public function update_product_stock( $product_id_with_stock, $stock_quantity = null, $operation = 'set' ) {
+ global $wpdb;
+
+ // Ensures a row exists to update.
+ add_post_meta( $product_id_with_stock, '_stock', 0, true );
+
+ if ( 'set' === $operation ) {
+ $new_stock = wc_stock_amount( $stock_quantity );
+
+ // Generate SQL.
+ $sql = $wpdb->prepare(
+ "UPDATE {$wpdb->postmeta} SET meta_value = %f WHERE post_id = %d AND meta_key='_stock'",
+ $new_stock,
+ $product_id_with_stock
+ );
+ } else {
+ $current_stock = wc_stock_amount(
+ $wpdb->get_var(
+ $wpdb->prepare(
+ "SELECT meta_value FROM {$wpdb->postmeta} WHERE post_id = %d AND meta_key='_stock';",
+ $product_id_with_stock
+ )
+ )
+ );
+
+ // Calculate new value for filter below. Set multiplier to subtract or add the meta_value.
+ switch ( $operation ) {
+ case 'increase':
+ $new_stock = $current_stock + wc_stock_amount( $stock_quantity );
+ $multiplier = 1;
+ break;
+ default:
+ $new_stock = $current_stock - wc_stock_amount( $stock_quantity );
+ $multiplier = -1;
+ break;
+ }
+
+ // Generate SQL.
+ $sql = $wpdb->prepare(
+ "UPDATE {$wpdb->postmeta} SET meta_value = meta_value %+f WHERE post_id = %d AND meta_key='_stock'",
+ wc_stock_amount( $stock_quantity ) * $multiplier, // This will either subtract or add depending on operation.
+ $product_id_with_stock
+ );
+ }
+
+ $sql = apply_filters( 'woocommerce_update_product_stock_query', $sql, $product_id_with_stock, $new_stock, $operation );
+
+ $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.NotPrepared
+
+ // Cache delete is required (not only) to set correct data for lookup table (which reads from cache).
+ // Sometimes I wonder if it shouldn't be part of update_lookup_table.
+ wp_cache_delete( $product_id_with_stock, 'post_meta' );
+
+ $this->update_lookup_table( $product_id_with_stock, 'wc_product_meta_lookup' );
+
+ /**
+ * Fire an action for this direct update so it can be detected by other code.
+ *
+ * @since 3.6
+ * @param int $product_id_with_stock Product ID that was updated directly.
+ */
+ do_action( 'woocommerce_updated_product_stock', $product_id_with_stock );
+
+ return $new_stock;
+ }
+
+ /**
+ * Update a product's sale count directly.
+ *
+ * Uses queries rather than update_post_meta so we can do this in one query for performance.
+ *
+ * @since 3.0.0 this supports set, increase and decrease.
+ * @param int $product_id Product ID.
+ * @param int|null $quantity Quantity.
+ * @param string $operation set, increase and decrease.
+ */
+ public function update_product_sales( $product_id, $quantity = null, $operation = 'set' ) {
+ global $wpdb;
+ add_post_meta( $product_id, 'total_sales', 0, true );
+
+ // Update stock in DB directly.
+ switch ( $operation ) {
+ case 'increase':
+ // phpcs:ignore WordPress.VIP.DirectDatabaseQuery.DirectQuery
+ $wpdb->query(
+ $wpdb->prepare(
+ "UPDATE {$wpdb->postmeta} SET meta_value = meta_value + %f WHERE post_id = %d AND meta_key='total_sales'",
+ $quantity,
+ $product_id
+ )
+ );
+ break;
+ case 'decrease':
+ // phpcs:ignore WordPress.VIP.DirectDatabaseQuery.DirectQuery
+ $wpdb->query(
+ $wpdb->prepare(
+ "UPDATE {$wpdb->postmeta} SET meta_value = meta_value - %f WHERE post_id = %d AND meta_key='total_sales'",
+ $quantity,
+ $product_id
+ )
+ );
+ break;
+ default:
+ // phpcs:ignore WordPress.VIP.DirectDatabaseQuery.DirectQuery
+ $wpdb->query(
+ $wpdb->prepare(
+ "UPDATE {$wpdb->postmeta} SET meta_value = %f WHERE post_id = %d AND meta_key='total_sales'",
+ $quantity,
+ $product_id
+ )
+ );
+ break;
+ }
+
+ wp_cache_delete( $product_id, 'post_meta' );
+
+ $this->update_lookup_table( $product_id, 'wc_product_meta_lookup' );
+
+ /**
+ * Fire an action for this direct update so it can be detected by other code.
+ *
+ * @since 3.6
+ * @param int $product_id Product ID that was updated directly.
+ */
+ do_action( 'woocommerce_updated_product_sales', $product_id );
+ }
+
+ /**
+ * Update a products average rating meta.
+ *
+ * @since 3.0.0
+ * @todo Deprecate unused function?
+ * @param WC_Product $product Product object.
+ */
+ public function update_average_rating( $product ) {
+ update_post_meta( $product->get_id(), '_wc_average_rating', $product->get_average_rating( 'edit' ) );
+ self::update_visibility( $product, true );
+ }
+
+ /**
+ * Update a products review count meta.
+ *
+ * @since 3.0.0
+ * @todo Deprecate unused function?
+ * @param WC_Product $product Product object.
+ */
+ public function update_review_count( $product ) {
+ update_post_meta( $product->get_id(), '_wc_review_count', $product->get_review_count( 'edit' ) );
+ }
+
+ /**
+ * Update a products rating counts.
+ *
+ * @since 3.0.0
+ * @todo Deprecate unused function?
+ * @param WC_Product $product Product object.
+ */
+ public function update_rating_counts( $product ) {
+ update_post_meta( $product->get_id(), '_wc_rating_count', $product->get_rating_counts( 'edit' ) );
+ }
+
+ /**
+ * Get shipping class ID by slug.
+ *
+ * @since 3.0.0
+ * @param string $slug Product shipping class slug.
+ * @return int|false
+ */
+ public function get_shipping_class_id_by_slug( $slug ) {
+ $shipping_class_term = get_term_by( 'slug', $slug, 'product_shipping_class' );
+ if ( $shipping_class_term ) {
+ return $shipping_class_term->term_id;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Returns an array of products.
+ *
+ * @param array $args Args to pass to WC_Product_Query().
+ * @return array|object
+ * @see wc_get_products
+ */
+ public function get_products( $args = array() ) {
+ $query = new WC_Product_Query( $args );
+ return $query->get_products();
+ }
+
+ /**
+ * Search product data for a term and return ids.
+ *
+ * @param string $term Search term.
+ * @param string $type Type of product.
+ * @param bool $include_variations Include variations in search or not.
+ * @param bool $all_statuses Should we search all statuses or limit to published.
+ * @param null|int $limit Limit returned results. @since 3.5.0.
+ * @param null|array $include Keep specific results. @since 3.6.0.
+ * @param null|array $exclude Discard specific results. @since 3.6.0.
+ * @return array of ids
+ */
+ public function search_products( $term, $type = '', $include_variations = false, $all_statuses = false, $limit = null, $include = null, $exclude = null ) {
+ global $wpdb;
+
+ $custom_results = apply_filters( 'woocommerce_product_pre_search_products', false, $term, $type, $include_variations, $all_statuses, $limit );
+
+ if ( is_array( $custom_results ) ) {
+ return $custom_results;
+ }
+
+ $post_types = $include_variations ? array( 'product', 'product_variation' ) : array( 'product' );
+ $join_query = '';
+ $type_where = '';
+ $status_where = '';
+ $limit_query = '';
+
+ // When searching variations we should include the parent's meta table for use in searches.
+ if ( $include_variations ) {
+ $join_query = " LEFT JOIN {$wpdb->wc_product_meta_lookup} parent_wc_product_meta_lookup
+ ON posts.post_type = 'product_variation' AND parent_wc_product_meta_lookup.product_id = posts.post_parent ";
+ }
+
+ /**
+ * Hook woocommerce_search_products_post_statuses.
+ *
+ * @since 3.7.0
+ * @param array $post_statuses List of post statuses.
+ */
+ $post_statuses = apply_filters(
+ 'woocommerce_search_products_post_statuses',
+ current_user_can( 'edit_private_products' ) ? array( 'private', 'publish' ) : array( 'publish' )
+ );
+
+ // See if search term contains OR keywords.
+ if ( stristr( $term, ' or ' ) ) {
+ $term_groups = preg_split( '/\s+or\s+/i', $term );
+ } else {
+ $term_groups = array( $term );
+ }
+
+ $search_where = '';
+ $search_queries = array();
+
+ foreach ( $term_groups as $term_group ) {
+ // Parse search terms.
+ if ( preg_match_all( '/".*?("|$)|((?<=[\t ",+])|^)[^\t ",+]+/', $term_group, $matches ) ) {
+ $search_terms = $this->get_valid_search_terms( $matches[0] );
+ $count = count( $search_terms );
+
+ // if the search string has only short terms or stopwords, or is 10+ terms long, match it as sentence.
+ if ( 9 < $count || 0 === $count ) {
+ $search_terms = array( $term_group );
+ }
+ } else {
+ $search_terms = array( $term_group );
+ }
+
+ $term_group_query = '';
+ $searchand = '';
+
+ foreach ( $search_terms as $search_term ) {
+ $like = '%' . $wpdb->esc_like( $search_term ) . '%';
+
+ // Variations should also search the parent's meta table for fallback fields.
+ if ( $include_variations ) {
+ $variation_query = $wpdb->prepare( ' OR ( wc_product_meta_lookup.sku = "" AND parent_wc_product_meta_lookup.sku LIKE %s ) ', $like );
+ } else {
+ $variation_query = '';
+ }
+
+ $term_group_query .= $wpdb->prepare( " {$searchand} ( ( posts.post_title LIKE %s) OR ( posts.post_excerpt LIKE %s) OR ( posts.post_content LIKE %s ) OR ( wc_product_meta_lookup.sku LIKE %s ) $variation_query)", $like, $like, $like, $like ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
+ $searchand = ' AND ';
+ }
+
+ if ( $term_group_query ) {
+ $search_queries[] = $term_group_query;
+ }
+ }
+
+ if ( ! empty( $search_queries ) ) {
+ $search_where = ' AND (' . implode( ') OR (', $search_queries ) . ') ';
+ }
+
+ if ( ! empty( $include ) && is_array( $include ) ) {
+ $search_where .= ' AND posts.ID IN(' . implode( ',', array_map( 'absint', $include ) ) . ') ';
+ }
+
+ if ( ! empty( $exclude ) && is_array( $exclude ) ) {
+ $search_where .= ' AND posts.ID NOT IN(' . implode( ',', array_map( 'absint', $exclude ) ) . ') ';
+ }
+
+ if ( 'virtual' === $type ) {
+ $type_where = ' AND ( wc_product_meta_lookup.virtual = 1 ) ';
+ } elseif ( 'downloadable' === $type ) {
+ $type_where = ' AND ( wc_product_meta_lookup.downloadable = 1 ) ';
+ }
+
+ if ( ! $all_statuses ) {
+ $status_where = " AND posts.post_status IN ('" . implode( "','", $post_statuses ) . "') ";
+ }
+
+ if ( $limit ) {
+ $limit_query = $wpdb->prepare( ' LIMIT %d ', $limit );
+ }
+
+ // phpcs:ignore WordPress.VIP.DirectDatabaseQuery.DirectQuery
+ $search_results = $wpdb->get_results(
+ // phpcs:disable
+ "SELECT DISTINCT posts.ID as product_id, posts.post_parent as parent_id FROM {$wpdb->posts} posts
+ LEFT JOIN {$wpdb->wc_product_meta_lookup} wc_product_meta_lookup ON posts.ID = wc_product_meta_lookup.product_id
+ $join_query
+ WHERE posts.post_type IN ('" . implode( "','", $post_types ) . "')
+ $search_where
+ $status_where
+ $type_where
+ ORDER BY posts.post_parent ASC, posts.post_title ASC
+ $limit_query
+ "
+ // phpcs:enable
+ );
+
+ $product_ids = wp_parse_id_list( array_merge( wp_list_pluck( $search_results, 'product_id' ), wp_list_pluck( $search_results, 'parent_id' ) ) );
+
+ if ( is_numeric( $term ) ) {
+ $post_id = absint( $term );
+ $post_type = get_post_type( $post_id );
+
+ if ( 'product_variation' === $post_type && $include_variations ) {
+ $product_ids[] = $post_id;
+ } elseif ( 'product' === $post_type ) {
+ $product_ids[] = $post_id;
+ }
+
+ $product_ids[] = wp_get_post_parent_id( $post_id );
+ }
+
+ return wp_parse_id_list( $product_ids );
+ }
+
+ /**
+ * Get the product type based on product ID.
+ *
+ * @since 3.0.0
+ * @param int $product_id Product ID.
+ * @return bool|string
+ */
+ public function get_product_type( $product_id ) {
+ $cache_key = WC_Cache_Helper::get_cache_prefix( 'product_' . $product_id ) . '_type_' . $product_id;
+ $product_type = wp_cache_get( $cache_key, 'products' );
+
+ if ( $product_type ) {
+ return $product_type;
+ }
+
+ $post_type = get_post_type( $product_id );
+
+ if ( 'product_variation' === $post_type ) {
+ $product_type = 'variation';
+ } elseif ( 'product' === $post_type ) {
+ $terms = get_the_terms( $product_id, 'product_type' );
+ $product_type = ! empty( $terms ) && ! is_wp_error( $terms ) ? sanitize_title( current( $terms )->name ) : 'simple';
+ } else {
+ $product_type = false;
+ }
+
+ wp_cache_set( $cache_key, $product_type, 'products' );
+
+ return $product_type;
+ }
+
+ /**
+ * Add ability to get products by 'reviews_allowed' in WC_Product_Query.
+ *
+ * @since 3.2.0
+ * @param string $where Where clause.
+ * @param WP_Query $wp_query WP_Query instance.
+ * @return string
+ */
+ public function reviews_allowed_query_where( $where, $wp_query ) {
+ global $wpdb;
+
+ if ( isset( $wp_query->query_vars['reviews_allowed'] ) && is_bool( $wp_query->query_vars['reviews_allowed'] ) ) {
+ if ( $wp_query->query_vars['reviews_allowed'] ) {
+ $where .= " AND $wpdb->posts.comment_status = 'open'";
+ } else {
+ $where .= " AND $wpdb->posts.comment_status = 'closed'";
+ }
+ }
+
+ return $where;
+ }
+
+ /**
+ * Get valid WP_Query args from a WC_Product_Query's query variables.
+ *
+ * @since 3.2.0
+ * @param array $query_vars Query vars from a WC_Product_Query.
+ * @return array
+ */
+ protected function get_wp_query_args( $query_vars ) {
+
+ // Map query vars to ones that get_wp_query_args or WP_Query recognize.
+ $key_mapping = array(
+ 'status' => 'post_status',
+ 'page' => 'paged',
+ 'include' => 'post__in',
+ 'stock_quantity' => 'stock',
+ 'average_rating' => 'wc_average_rating',
+ 'review_count' => 'wc_review_count',
+ );
+ foreach ( $key_mapping as $query_key => $db_key ) {
+ if ( isset( $query_vars[ $query_key ] ) ) {
+ $query_vars[ $db_key ] = $query_vars[ $query_key ];
+ unset( $query_vars[ $query_key ] );
+ }
+ }
+
+ // Map boolean queries that are stored as 'yes'/'no' in the DB to 'yes' or 'no'.
+ $boolean_queries = array(
+ 'virtual',
+ 'downloadable',
+ 'sold_individually',
+ 'manage_stock',
+ );
+ foreach ( $boolean_queries as $boolean_query ) {
+ if ( isset( $query_vars[ $boolean_query ] ) && '' !== $query_vars[ $boolean_query ] ) {
+ $query_vars[ $boolean_query ] = $query_vars[ $boolean_query ] ? 'yes' : 'no';
+ }
+ }
+
+ // These queries cannot be auto-generated so we have to remove them and build them manually.
+ $manual_queries = array(
+ 'sku' => '',
+ 'featured' => '',
+ 'visibility' => '',
+ );
+ foreach ( $manual_queries as $key => $manual_query ) {
+ if ( isset( $query_vars[ $key ] ) ) {
+ $manual_queries[ $key ] = $query_vars[ $key ];
+ unset( $query_vars[ $key ] );
+ }
+ }
+
+ $wp_query_args = parent::get_wp_query_args( $query_vars );
+
+ if ( ! isset( $wp_query_args['date_query'] ) ) {
+ $wp_query_args['date_query'] = array();
+ }
+ if ( ! isset( $wp_query_args['meta_query'] ) ) {
+ $wp_query_args['meta_query'] = array(); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
+ }
+
+ // Handle product types.
+ if ( 'variation' === $query_vars['type'] ) {
+ $wp_query_args['post_type'] = 'product_variation';
+ } elseif ( is_array( $query_vars['type'] ) && in_array( 'variation', $query_vars['type'], true ) ) {
+ $wp_query_args['post_type'] = array( 'product_variation', 'product' );
+ $wp_query_args['tax_query'][] = array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
+ 'relation' => 'OR',
+ array(
+ 'taxonomy' => 'product_type',
+ 'field' => 'slug',
+ 'terms' => $query_vars['type'],
+ ),
+ array(
+ 'taxonomy' => 'product_type',
+ 'field' => 'id',
+ 'operator' => 'NOT EXISTS',
+ ),
+ );
+ } else {
+ $wp_query_args['post_type'] = 'product';
+ $wp_query_args['tax_query'][] = array(
+ 'taxonomy' => 'product_type',
+ 'field' => 'slug',
+ 'terms' => $query_vars['type'],
+ );
+ }
+
+ // Handle product categories.
+ if ( ! empty( $query_vars['category'] ) ) {
+ $wp_query_args['tax_query'][] = array(
+ 'taxonomy' => 'product_cat',
+ 'field' => 'slug',
+ 'terms' => $query_vars['category'],
+ );
+ }
+
+ // Handle product tags.
+ if ( ! empty( $query_vars['tag'] ) ) {
+ unset( $wp_query_args['tag'] );
+ $wp_query_args['tax_query'][] = array(
+ 'taxonomy' => 'product_tag',
+ 'field' => 'slug',
+ 'terms' => $query_vars['tag'],
+ );
+ }
+
+ // Handle shipping classes.
+ if ( ! empty( $query_vars['shipping_class'] ) ) {
+ $wp_query_args['tax_query'][] = array(
+ 'taxonomy' => 'product_shipping_class',
+ 'field' => 'slug',
+ 'terms' => $query_vars['shipping_class'],
+ );
+ }
+
+ // Handle total_sales.
+ // This query doesn't get auto-generated since the meta key doesn't have the underscore prefix.
+ if ( isset( $query_vars['total_sales'] ) && '' !== $query_vars['total_sales'] ) {
+ $wp_query_args['meta_query'][] = array(
+ 'key' => 'total_sales',
+ 'value' => absint( $query_vars['total_sales'] ),
+ 'compare' => '=',
+ );
+ }
+
+ // Handle SKU.
+ if ( $manual_queries['sku'] ) {
+ // Check for existing values if wildcard is used.
+ if ( '*' === $manual_queries['sku'] ) {
+ $wp_query_args['meta_query'][] = array(
+ array(
+ 'key' => '_sku',
+ 'compare' => 'EXISTS',
+ ),
+ array(
+ 'key' => '_sku',
+ 'value' => '',
+ 'compare' => '!=',
+ ),
+ );
+ } else {
+ $wp_query_args['meta_query'][] = array(
+ 'key' => '_sku',
+ 'value' => $manual_queries['sku'],
+ 'compare' => 'LIKE',
+ );
+ }
+ }
+
+ // Handle featured.
+ if ( '' !== $manual_queries['featured'] ) {
+ $product_visibility_term_ids = wc_get_product_visibility_term_ids();
+ if ( $manual_queries['featured'] ) {
+ $wp_query_args['tax_query'][] = array(
+ 'taxonomy' => 'product_visibility',
+ 'field' => 'term_taxonomy_id',
+ 'terms' => array( $product_visibility_term_ids['featured'] ),
+ );
+ $wp_query_args['tax_query'][] = array(
+ 'taxonomy' => 'product_visibility',
+ 'field' => 'term_taxonomy_id',
+ 'terms' => array( $product_visibility_term_ids['exclude-from-catalog'] ),
+ 'operator' => 'NOT IN',
+ );
+ } else {
+ $wp_query_args['tax_query'][] = array(
+ 'taxonomy' => 'product_visibility',
+ 'field' => 'term_taxonomy_id',
+ 'terms' => array( $product_visibility_term_ids['featured'] ),
+ 'operator' => 'NOT IN',
+ );
+ }
+ }
+
+ // Handle visibility.
+ if ( $manual_queries['visibility'] ) {
+ switch ( $manual_queries['visibility'] ) {
+ case 'search':
+ $wp_query_args['tax_query'][] = array(
+ 'taxonomy' => 'product_visibility',
+ 'field' => 'slug',
+ 'terms' => array( 'exclude-from-search' ),
+ 'operator' => 'NOT IN',
+ );
+ break;
+ case 'catalog':
+ $wp_query_args['tax_query'][] = array(
+ 'taxonomy' => 'product_visibility',
+ 'field' => 'slug',
+ 'terms' => array( 'exclude-from-catalog' ),
+ 'operator' => 'NOT IN',
+ );
+ break;
+ case 'visible':
+ $wp_query_args['tax_query'][] = array(
+ 'taxonomy' => 'product_visibility',
+ 'field' => 'slug',
+ 'terms' => array( 'exclude-from-catalog', 'exclude-from-search' ),
+ 'operator' => 'NOT IN',
+ );
+ break;
+ case 'hidden':
+ $wp_query_args['tax_query'][] = array(
+ 'taxonomy' => 'product_visibility',
+ 'field' => 'slug',
+ 'terms' => array( 'exclude-from-catalog', 'exclude-from-search' ),
+ 'operator' => 'AND',
+ );
+ break;
+ }
+ }
+
+ // Handle date queries.
+ $date_queries = array(
+ 'date_created' => 'post_date',
+ 'date_modified' => 'post_modified',
+ 'date_on_sale_from' => '_sale_price_dates_from',
+ 'date_on_sale_to' => '_sale_price_dates_to',
+ );
+ foreach ( $date_queries as $query_var_key => $db_key ) {
+ if ( isset( $query_vars[ $query_var_key ] ) && '' !== $query_vars[ $query_var_key ] ) {
+
+ // Remove any existing meta queries for the same keys to prevent conflicts.
+ $existing_queries = wp_list_pluck( $wp_query_args['meta_query'], 'key', true );
+ foreach ( $existing_queries as $query_index => $query_contents ) {
+ unset( $wp_query_args['meta_query'][ $query_index ] );
+ }
+
+ $wp_query_args = $this->parse_date_for_wp_query( $query_vars[ $query_var_key ], $db_key, $wp_query_args );
+ }
+ }
+
+ // Handle paginate.
+ if ( ! isset( $query_vars['paginate'] ) || ! $query_vars['paginate'] ) {
+ $wp_query_args['no_found_rows'] = true;
+ }
+
+ // Handle reviews_allowed.
+ if ( isset( $query_vars['reviews_allowed'] ) && is_bool( $query_vars['reviews_allowed'] ) ) {
+ add_filter( 'posts_where', array( $this, 'reviews_allowed_query_where' ), 10, 2 );
+ }
+
+ // Handle orderby.
+ if ( isset( $query_vars['orderby'] ) && 'include' === $query_vars['orderby'] ) {
+ $wp_query_args['orderby'] = 'post__in';
+ }
+
+ return apply_filters( 'woocommerce_product_data_store_cpt_get_products_query', $wp_query_args, $query_vars, $this );
+ }
+
+ /**
+ * Query for Products matching specific criteria.
+ *
+ * @since 3.2.0
+ *
+ * @param array $query_vars Query vars from a WC_Product_Query.
+ *
+ * @return array|object
+ */
+ public function query( $query_vars ) {
+ $args = $this->get_wp_query_args( $query_vars );
+
+ if ( ! empty( $args['errors'] ) ) {
+ $query = (object) array(
+ 'posts' => array(),
+ 'found_posts' => 0,
+ 'max_num_pages' => 0,
+ );
+ } else {
+ $query = new WP_Query( $args );
+ }
+
+ if ( isset( $query_vars['return'] ) && 'objects' === $query_vars['return'] && ! empty( $query->posts ) ) {
+ // Prime caches before grabbing objects.
+ update_post_caches( $query->posts, array( 'product', 'product_variation' ) );
+ }
+
+ $products = ( isset( $query_vars['return'] ) && 'ids' === $query_vars['return'] ) ? $query->posts : array_filter( array_map( 'wc_get_product', $query->posts ) );
+
+ if ( isset( $query_vars['paginate'] ) && $query_vars['paginate'] ) {
+ return (object) array(
+ 'products' => $products,
+ 'total' => $query->found_posts,
+ 'max_num_pages' => $query->max_num_pages,
+ );
+ }
+
+ return $products;
+ }
+
+ /**
+ * Get data to save to a lookup table.
+ *
+ * @since 3.6.0
+ * @param int $id ID of object to update.
+ * @param string $table Lookup table name.
+ * @return array
+ */
+ protected function get_data_for_lookup_table( $id, $table ) {
+ if ( 'wc_product_meta_lookup' === $table ) {
+ $price_meta = (array) get_post_meta( $id, '_price', false );
+ $manage_stock = get_post_meta( $id, '_manage_stock', true );
+ $stock = 'yes' === $manage_stock ? wc_stock_amount( get_post_meta( $id, '_stock', true ) ) : null;
+ $price = wc_format_decimal( get_post_meta( $id, '_price', true ) );
+ $sale_price = wc_format_decimal( get_post_meta( $id, '_sale_price', true ) );
+ return array(
+ 'product_id' => absint( $id ),
+ 'sku' => get_post_meta( $id, '_sku', true ),
+ 'virtual' => 'yes' === get_post_meta( $id, '_virtual', true ) ? 1 : 0,
+ 'downloadable' => 'yes' === get_post_meta( $id, '_downloadable', true ) ? 1 : 0,
+ 'min_price' => reset( $price_meta ),
+ 'max_price' => end( $price_meta ),
+ 'onsale' => $sale_price && $price === $sale_price ? 1 : 0,
+ 'stock_quantity' => $stock,
+ 'stock_status' => get_post_meta( $id, '_stock_status', true ),
+ 'rating_count' => array_sum( (array) get_post_meta( $id, '_wc_rating_count', true ) ),
+ 'average_rating' => get_post_meta( $id, '_wc_average_rating', true ),
+ 'total_sales' => get_post_meta( $id, 'total_sales', true ),
+ 'tax_status' => get_post_meta( $id, '_tax_status', true ),
+ 'tax_class' => get_post_meta( $id, '_tax_class', true ),
+ );
+ }
+ return array();
+ }
+
+ /**
+ * Get primary key name for lookup table.
+ *
+ * @since 3.6.0
+ * @param string $table Lookup table name.
+ * @return string
+ */
+ protected function get_primary_key_for_lookup_table( $table ) {
+ if ( 'wc_product_meta_lookup' === $table ) {
+ return 'product_id';
+ }
+ return '';
+ }
+
+ /**
+ * Returns query statement for getting current `_stock` of a product.
+ *
+ * @internal MAX function below is used to make sure result is a scalar.
+ * @param int $product_id Product ID.
+ * @return string|void Query statement.
+ */
+ public function get_query_for_stock( $product_id ) {
+ global $wpdb;
+ return $wpdb->prepare(
+ "
+ SELECT COALESCE ( MAX( meta_value ), 0 ) FROM $wpdb->postmeta as meta_table
+ WHERE meta_table.meta_key = '_stock'
+ AND meta_table.post_id = %d
+ ",
+ $product_id
+ );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-product-grouped-data-store-cpt.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-product-grouped-data-store-cpt.php
new file mode 100644
index 0000000..3f7ea7b
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-product-grouped-data-store-cpt.php
@@ -0,0 +1,100 @@
+ 'children',
+ );
+
+ $props_to_update = $force ? $meta_key_to_props : $this->get_props_to_update( $product, $meta_key_to_props );
+
+ foreach ( $props_to_update as $meta_key => $prop ) {
+ $value = $product->{"get_$prop"}( 'edit' );
+ $updated = update_post_meta( $product->get_id(), $meta_key, $value );
+ if ( $updated ) {
+ $this->updated_props[] = $prop;
+ }
+ }
+
+ parent::update_post_meta( $product, $force );
+ }
+
+ /**
+ * Handle updated meta props after updating meta data.
+ *
+ * @since 3.0.0
+ * @param WC_Product $product Product object.
+ */
+ protected function handle_updated_props( &$product ) {
+ if ( in_array( 'children', $this->updated_props, true ) ) {
+ $this->update_prices_from_children( $product );
+ }
+ parent::handle_updated_props( $product );
+ }
+
+ /**
+ * Sync grouped product prices with children.
+ *
+ * @since 3.0.0
+ * @param WC_Product|int $product Product object or product ID.
+ */
+ public function sync_price( &$product ) {
+ $this->update_prices_from_children( $product );
+ }
+
+ /**
+ * Loop over child products and update the grouped product prices.
+ *
+ * @param WC_Product $product Product object.
+ */
+ protected function update_prices_from_children( &$product ) {
+ $child_prices = array();
+ foreach ( $product->get_children( 'edit' ) as $child_id ) {
+ $child = wc_get_product( $child_id );
+ if ( $child ) {
+ $child_prices[] = $child->get_price( 'edit' );
+ }
+ }
+ $child_prices = array_filter( $child_prices );
+ delete_post_meta( $product->get_id(), '_price' );
+ delete_post_meta( $product->get_id(), '_sale_price' );
+ delete_post_meta( $product->get_id(), '_regular_price' );
+
+ if ( ! empty( $child_prices ) ) {
+ add_post_meta( $product->get_id(), '_price', min( $child_prices ) );
+ add_post_meta( $product->get_id(), '_price', max( $child_prices ) );
+ }
+
+ $this->update_lookup_table( $product->get_id(), 'wc_product_meta_lookup' );
+
+ /**
+ * Fire an action for this direct update so it can be detected by other code.
+ *
+ * @since 3.6
+ * @param int $product_id Product ID that was updated directly.
+ */
+ do_action( 'woocommerce_updated_product_price', $product->get_id() );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-product-variable-data-store-cpt.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-product-variable-data-store-cpt.php
new file mode 100644
index 0000000..eeece0d
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-product-variable-data-store-cpt.php
@@ -0,0 +1,701 @@
+get_id(), '_product_attributes', true );
+
+ if ( ! empty( $meta_attributes ) && is_array( $meta_attributes ) ) {
+ $attributes = array();
+ $force_update = false;
+ foreach ( $meta_attributes as $meta_attribute_key => $meta_attribute_value ) {
+ $meta_value = array_merge(
+ array(
+ 'name' => '',
+ 'value' => '',
+ 'position' => 0,
+ 'is_visible' => 0,
+ 'is_variation' => 0,
+ 'is_taxonomy' => 0,
+ ),
+ (array) $meta_attribute_value
+ );
+
+ // Maintain data integrity. 4.9 changed sanitization functions - update the values here so variations function correctly.
+ if ( $meta_value['is_variation'] && strstr( $meta_value['name'], '/' ) && sanitize_title( $meta_value['name'] ) !== $meta_attribute_key ) {
+ global $wpdb;
+
+ $old_slug = 'attribute_' . $meta_attribute_key;
+ $new_slug = 'attribute_' . sanitize_title( $meta_value['name'] );
+ $old_meta_rows = $wpdb->get_results( $wpdb->prepare( "SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE meta_key = %s;", $old_slug ) ); // WPCS: db call ok, cache ok.
+
+ if ( $old_meta_rows ) {
+ foreach ( $old_meta_rows as $old_meta_row ) {
+ update_post_meta( $old_meta_row->post_id, $new_slug, $old_meta_row->meta_value );
+ }
+ }
+
+ $force_update = true;
+ }
+
+ // Check if is a taxonomy attribute.
+ if ( ! empty( $meta_value['is_taxonomy'] ) ) {
+ if ( ! taxonomy_exists( $meta_value['name'] ) ) {
+ continue;
+ }
+ $id = wc_attribute_taxonomy_id_by_name( $meta_value['name'] );
+ $options = wc_get_object_terms( $product->get_id(), $meta_value['name'], 'term_id' );
+ } else {
+ $id = 0;
+ $options = wc_get_text_attributes( $meta_value['value'] );
+ }
+
+ $attribute = new WC_Product_Attribute();
+ $attribute->set_id( $id );
+ $attribute->set_name( $meta_value['name'] );
+ $attribute->set_options( $options );
+ $attribute->set_position( $meta_value['position'] );
+ $attribute->set_visible( $meta_value['is_visible'] );
+ $attribute->set_variation( $meta_value['is_variation'] );
+ $attributes[] = $attribute;
+ }
+ $product->set_attributes( $attributes );
+
+ if ( $force_update ) {
+ $this->update_attributes( $product, true );
+ }
+ }
+ }
+
+ /**
+ * Read product data.
+ *
+ * @param WC_Product $product Product object.
+ *
+ * @since 3.0.0
+ */
+ protected function read_product_data( &$product ) {
+ parent::read_product_data( $product );
+
+ // Make sure data which does not apply to variables is unset.
+ $product->set_regular_price( '' );
+ $product->set_sale_price( '' );
+ }
+
+ /**
+ * Loads variation child IDs.
+ *
+ * @param WC_Product $product Product object.
+ * @param bool $force_read True to bypass the transient.
+ *
+ * @return array
+ */
+ public function read_children( &$product, $force_read = false ) {
+ $children_transient_name = 'wc_product_children_' . $product->get_id();
+ $children = get_transient( $children_transient_name );
+
+ if ( empty( $children ) || ! is_array( $children ) || ! isset( $children['all'] ) || ! isset( $children['visible'] ) || $force_read ) {
+ $all_args = array(
+ 'post_parent' => $product->get_id(),
+ 'post_type' => 'product_variation',
+ 'orderby' => array(
+ 'menu_order' => 'ASC',
+ 'ID' => 'ASC',
+ ),
+ 'fields' => 'ids',
+ 'post_status' => array( 'publish', 'private' ),
+ 'numberposts' => -1, // phpcs:ignore WordPress.VIP.PostsPerPage.posts_per_page_numberposts
+ );
+
+ $visible_only_args = $all_args;
+ $visible_only_args['post_status'] = 'publish';
+
+ if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
+ $visible_only_args['tax_query'][] = array(
+ 'taxonomy' => 'product_visibility',
+ 'field' => 'name',
+ 'terms' => 'outofstock',
+ 'operator' => 'NOT IN',
+ );
+ }
+ $children['all'] = get_posts( apply_filters( 'woocommerce_variable_children_args', $all_args, $product, false ) );
+ $children['visible'] = get_posts( apply_filters( 'woocommerce_variable_children_args', $visible_only_args, $product, true ) );
+
+ set_transient( $children_transient_name, $children, DAY_IN_SECONDS * 30 );
+ }
+
+ $children['all'] = wp_parse_id_list( (array) $children['all'] );
+ $children['visible'] = wp_parse_id_list( (array) $children['visible'] );
+
+ return $children;
+ }
+
+ /**
+ * Loads an array of attributes used for variations, as well as their possible values.
+ *
+ * @param WC_Product $product Product object.
+ *
+ * @return array
+ */
+ public function read_variation_attributes( &$product ) {
+ global $wpdb;
+
+ $variation_attributes = array();
+ $attributes = $product->get_attributes();
+ $child_ids = $product->get_children();
+ $cache_key = WC_Cache_Helper::get_cache_prefix( 'product_' . $product->get_id() ) . 'product_variation_attributes_' . $product->get_id();
+ $cache_group = 'products';
+ $cached_data = wp_cache_get( $cache_key, $cache_group );
+
+ if ( false !== $cached_data ) {
+ return $cached_data;
+ }
+
+ if ( ! empty( $attributes ) ) {
+ foreach ( $attributes as $attribute ) {
+ if ( empty( $attribute['is_variation'] ) ) {
+ continue;
+ }
+
+ // Get possible values for this attribute, for only visible variations.
+ if ( ! empty( $child_ids ) ) {
+ $format = array_fill( 0, count( $child_ids ), '%d' );
+ $query_in = '(' . implode( ',', $format ) . ')';
+ $query_args = array( 'attribute_name' => wc_variation_attribute_name( $attribute['name'] ) ) + $child_ids;
+ $values = array_unique(
+ $wpdb->get_col(
+ $wpdb->prepare(
+ "SELECT meta_value FROM {$wpdb->postmeta} WHERE meta_key = %s AND post_id IN {$query_in}", // @codingStandardsIgnoreLine.
+ $query_args
+ )
+ )
+ );
+ } else {
+ $values = array();
+ }
+
+ // Empty value indicates that all options for given attribute are available.
+ if ( in_array( null, $values, true ) || in_array( '', $values, true ) || empty( $values ) ) {
+ $values = $attribute['is_taxonomy'] ? wc_get_object_terms( $product->get_id(), $attribute['name'], 'slug' ) : wc_get_text_attributes( $attribute['value'] );
+ // Get custom attributes (non taxonomy) as defined.
+ } elseif ( ! $attribute['is_taxonomy'] ) {
+ $text_attributes = wc_get_text_attributes( $attribute['value'] );
+ $assigned_text_attributes = $values;
+ $values = array();
+
+ // Pre 2.4 handling where 'slugs' were saved instead of the full text attribute.
+ if ( version_compare( get_post_meta( $product->get_id(), '_product_version', true ), '2.4.0', '<' ) ) {
+ $assigned_text_attributes = array_map( 'sanitize_title', $assigned_text_attributes );
+ foreach ( $text_attributes as $text_attribute ) {
+ if ( in_array( sanitize_title( $text_attribute ), $assigned_text_attributes, true ) ) {
+ $values[] = $text_attribute;
+ }
+ }
+ } else {
+ foreach ( $text_attributes as $text_attribute ) {
+ if ( in_array( $text_attribute, $assigned_text_attributes, true ) ) {
+ $values[] = $text_attribute;
+ }
+ }
+ }
+ }
+ $variation_attributes[ $attribute['name'] ] = array_unique( $values );
+ }
+ }
+
+ wp_cache_set( $cache_key, $variation_attributes, $cache_group );
+
+ return $variation_attributes;
+ }
+
+ /**
+ * Get an array of all sale and regular prices from all variations. This is used for example when displaying the price range at variable product level or seeing if the variable product is on sale.
+ *
+ * Can be filtered by plugins which modify costs, but otherwise will include the raw meta costs unlike get_price() which runs costs through the woocommerce_get_price filter.
+ * This is to ensure modified prices are not cached, unless intended.
+ *
+ * @param WC_Product $product Product object.
+ * @param bool $for_display If true, prices will be adapted for display based on the `woocommerce_tax_display_shop` setting (including or excluding taxes).
+ *
+ * @return array of prices
+ * @since 3.0.0
+ */
+ public function read_price_data( &$product, $for_display = false ) {
+
+ /**
+ * Transient name for storing prices for this product (note: Max transient length is 45)
+ *
+ * @since 2.5.0 a single transient is used per product for all prices, rather than many transients per product.
+ */
+ $transient_name = 'wc_var_prices_' . $product->get_id();
+ $transient_version = WC_Cache_Helper::get_transient_version( 'product' );
+ $price_hash = $this->get_price_hash( $product, $for_display );
+
+ // Check if prices array is stale.
+ if ( ! isset( $this->prices_array['version'] ) || $this->prices_array['version'] !== $transient_version ) {
+ $this->prices_array = array(
+ 'version' => $transient_version,
+ );
+ }
+
+ /**
+ * $this->prices_array is an array of values which may have been modified from what is stored in transients - this may not match $transient_cached_prices_array.
+ * If the value has already been generated, we don't need to grab the values again so just return them. They are already filtered.
+ */
+ if ( empty( $this->prices_array[ $price_hash ] ) ) {
+ $transient_cached_prices_array = array_filter( (array) json_decode( strval( get_transient( $transient_name ) ), true ) );
+
+ // If the product version has changed since the transient was last saved, reset the transient cache.
+ if ( ! isset( $transient_cached_prices_array['version'] ) || $transient_version !== $transient_cached_prices_array['version'] ) {
+ $transient_cached_prices_array = array(
+ 'version' => $transient_version,
+ );
+ }
+
+ // If the prices are not stored for this hash, generate them and add to the transient.
+ if ( empty( $transient_cached_prices_array[ $price_hash ] ) ) {
+ $prices_array = array(
+ 'price' => array(),
+ 'regular_price' => array(),
+ 'sale_price' => array(),
+ );
+
+ $variation_ids = $product->get_visible_children();
+
+ if ( is_callable( '_prime_post_caches' ) ) {
+ _prime_post_caches( $variation_ids );
+ }
+
+ foreach ( $variation_ids as $variation_id ) {
+ $variation = wc_get_product( $variation_id );
+
+ if ( $variation ) {
+ $price = apply_filters( 'woocommerce_variation_prices_price', $variation->get_price( 'edit' ), $variation, $product );
+ $regular_price = apply_filters( 'woocommerce_variation_prices_regular_price', $variation->get_regular_price( 'edit' ), $variation, $product );
+ $sale_price = apply_filters( 'woocommerce_variation_prices_sale_price', $variation->get_sale_price( 'edit' ), $variation, $product );
+
+ // Skip empty prices.
+ if ( '' === $price ) {
+ continue;
+ }
+
+ // If sale price does not equal price, the product is not yet on sale.
+ if ( $sale_price === $regular_price || $sale_price !== $price ) {
+ $sale_price = $regular_price;
+ }
+
+ // If we are getting prices for display, we need to account for taxes.
+ if ( $for_display ) {
+ if ( 'incl' === get_option( 'woocommerce_tax_display_shop' ) ) {
+ $price = '' === $price ? '' : wc_get_price_including_tax(
+ $variation,
+ array(
+ 'qty' => 1,
+ 'price' => $price,
+ )
+ );
+ $regular_price = '' === $regular_price ? '' : wc_get_price_including_tax(
+ $variation,
+ array(
+ 'qty' => 1,
+ 'price' => $regular_price,
+ )
+ );
+ $sale_price = '' === $sale_price ? '' : wc_get_price_including_tax(
+ $variation,
+ array(
+ 'qty' => 1,
+ 'price' => $sale_price,
+ )
+ );
+ } else {
+ $price = '' === $price ? '' : wc_get_price_excluding_tax(
+ $variation,
+ array(
+ 'qty' => 1,
+ 'price' => $price,
+ )
+ );
+ $regular_price = '' === $regular_price ? '' : wc_get_price_excluding_tax(
+ $variation,
+ array(
+ 'qty' => 1,
+ 'price' => $regular_price,
+ )
+ );
+ $sale_price = '' === $sale_price ? '' : wc_get_price_excluding_tax(
+ $variation,
+ array(
+ 'qty' => 1,
+ 'price' => $sale_price,
+ )
+ );
+ }
+ }
+
+ $prices_array['price'][ $variation_id ] = wc_format_decimal( $price, wc_get_price_decimals() );
+ $prices_array['regular_price'][ $variation_id ] = wc_format_decimal( $regular_price, wc_get_price_decimals() );
+ $prices_array['sale_price'][ $variation_id ] = wc_format_decimal( $sale_price, wc_get_price_decimals() );
+
+ $prices_array = apply_filters( 'woocommerce_variation_prices_array', $prices_array, $variation, $for_display );
+ }
+ }
+
+ // Add all pricing data to the transient array.
+ foreach ( $prices_array as $key => $values ) {
+ $transient_cached_prices_array[ $price_hash ][ $key ] = $values;
+ }
+
+ set_transient( $transient_name, wp_json_encode( $transient_cached_prices_array ), DAY_IN_SECONDS * 30 );
+ }
+
+ /**
+ * Give plugins one last chance to filter the variation prices array which has been generated and store locally to the class.
+ * This value may differ from the transient cache. It is filtered once before storing locally.
+ */
+ $this->prices_array[ $price_hash ] = apply_filters( 'woocommerce_variation_prices', $transient_cached_prices_array[ $price_hash ], $product, $for_display );
+ }
+ return $this->prices_array[ $price_hash ];
+ }
+
+ /**
+ * Create unique cache key based on the tax location (affects displayed/cached prices), product version and active price filters.
+ * DEVELOPERS should filter this hash if offering conditional pricing to keep it unique.
+ *
+ * @param WC_Product $product Product object.
+ * @param bool $for_display If taxes should be calculated or not.
+ *
+ * @since 3.0.0
+ * @return string
+ */
+ protected function get_price_hash( &$product, $for_display = false ) {
+ global $wp_filter;
+
+ $price_hash = $for_display && wc_tax_enabled() ? array( get_option( 'woocommerce_tax_display_shop', 'excl' ), WC_Tax::get_rates() ) : array( false );
+ $filter_names = array( 'woocommerce_variation_prices_price', 'woocommerce_variation_prices_regular_price', 'woocommerce_variation_prices_sale_price' );
+
+ foreach ( $filter_names as $filter_name ) {
+ if ( ! empty( $wp_filter[ $filter_name ] ) ) {
+ $price_hash[ $filter_name ] = array();
+
+ foreach ( $wp_filter[ $filter_name ] as $priority => $callbacks ) {
+ $price_hash[ $filter_name ][] = array_values( wp_list_pluck( $callbacks, 'function' ) );
+ }
+ }
+ }
+
+ return md5( wp_json_encode( apply_filters( 'woocommerce_get_variation_prices_hash', $price_hash, $product, $for_display ) ) );
+ }
+
+ /**
+ * Does a child have a weight set?
+ *
+ * @param WC_Product $product Product object.
+ *
+ * @since 3.0.0
+ * @return boolean
+ */
+ public function child_has_weight( $product ) {
+ global $wpdb;
+ $children = $product->get_visible_children();
+ if ( ! $children ) {
+ return false;
+ }
+
+ $format = array_fill( 0, count( $children ), '%d' );
+ $query_in = '(' . implode( ',', $format ) . ')';
+
+ return null !== $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_weight' AND meta_value > 0 AND post_id IN {$query_in}", $children ) ); // @codingStandardsIgnoreLine.
+ }
+
+ /**
+ * Does a child have dimensions set?
+ *
+ * @param WC_Product $product Product object.
+ *
+ * @since 3.0.0
+ * @return boolean
+ */
+ public function child_has_dimensions( $product ) {
+ global $wpdb;
+ $children = $product->get_visible_children();
+ if ( ! $children ) {
+ return false;
+ }
+
+ $format = array_fill( 0, count( $children ), '%d' );
+ $query_in = '(' . implode( ',', $format ) . ')';
+
+ return null !== $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key IN ( '_length', '_width', '_height' ) AND meta_value > 0 AND post_id IN {$query_in}", $children ) ); // @codingStandardsIgnoreLine.
+ }
+
+ /**
+ * Is a child in stock?
+ *
+ * @param WC_Product $product Product object.
+ *
+ * @since 3.0.0
+ * @return boolean
+ */
+ public function child_is_in_stock( $product ) {
+ return $this->child_has_stock_status( $product, 'instock' );
+ }
+
+ /**
+ * Does a child have a stock status?
+ *
+ * @param WC_Product $product Product object.
+ * @param string $status 'instock', 'outofstock', or 'onbackorder'.
+ *
+ * @since 3.3.0
+ * @return boolean
+ */
+ public function child_has_stock_status( $product, $status ) {
+ global $wpdb;
+
+ $children = $product->get_children();
+
+ if ( $children ) {
+ $format = array_fill( 0, count( $children ), '%d' );
+ $query_in = '(' . implode( ',', $format ) . ')';
+ $query_args = array( 'stock_status' => $status ) + $children;
+ // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
+ if ( get_option( 'woocommerce_product_lookup_table_is_generating' ) ) {
+ $query = "SELECT COUNT( post_id ) FROM {$wpdb->postmeta} WHERE meta_key = '_stock_status' AND meta_value = %s AND post_id IN {$query_in}";
+ } else {
+ $query = "SELECT COUNT( product_id ) FROM {$wpdb->wc_product_meta_lookup} WHERE stock_status = %s AND product_id IN {$query_in}";
+ }
+ $children_with_status = $wpdb->get_var(
+ $wpdb->prepare(
+ $query,
+ $query_args
+ )
+ );
+ // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
+ } else {
+ $children_with_status = 0;
+ }
+
+ return (bool) $children_with_status;
+ }
+
+ /**
+ * Syncs all variation names if the parent name is changed.
+ *
+ * @param WC_Product $product Product object.
+ * @param string $previous_name Variation previous name.
+ * @param string $new_name Variation new name.
+ *
+ * @since 3.0.0
+ */
+ public function sync_variation_names( &$product, $previous_name = '', $new_name = '' ) {
+ if ( $new_name !== $previous_name ) {
+ global $wpdb;
+
+ $wpdb->query(
+ $wpdb->prepare(
+ "UPDATE {$wpdb->posts}
+ SET post_title = REPLACE( post_title, %s, %s )
+ WHERE post_type = 'product_variation'
+ AND post_parent = %d",
+ $previous_name ? $previous_name : 'AUTO-DRAFT',
+ $new_name,
+ $product->get_id()
+ )
+ );
+ }
+ }
+
+ /**
+ * Stock managed at the parent level - update children being managed by this product.
+ * This sync function syncs downwards (from parent to child) when the variable product is saved.
+ *
+ * @param WC_Product $product Product object.
+ *
+ * @since 3.0.0
+ */
+ public function sync_managed_variation_stock_status( &$product ) {
+ global $wpdb;
+
+ if ( $product->get_manage_stock() ) {
+ $children = $product->get_children();
+ $changed = false;
+
+ if ( $children ) {
+ $status = $product->get_stock_status();
+ $format = array_fill( 0, count( $children ), '%d' );
+ $query_in = '(' . implode( ',', $format ) . ')';
+ $managed_children = array_unique( $wpdb->get_col( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_manage_stock' AND meta_value != 'yes' AND post_id IN {$query_in}", $children ) ) ); // @codingStandardsIgnoreLine.
+ foreach ( $managed_children as $managed_child ) {
+ if ( update_post_meta( $managed_child, '_stock_status', $status ) ) {
+ $this->update_lookup_table( $managed_child, 'wc_product_meta_lookup' );
+ $changed = true;
+ }
+ }
+ }
+
+ if ( $changed ) {
+ $children = $this->read_children( $product, true );
+ $product->set_children( $children['all'] );
+ $product->set_visible_children( $children['visible'] );
+ }
+ }
+ }
+
+ /**
+ * Sync variable product prices with children.
+ *
+ * @param WC_Product $product Product object.
+ *
+ * @since 3.0.0
+ */
+ public function sync_price( &$product ) {
+ global $wpdb;
+
+ $children = $product->get_visible_children();
+ if ( $children ) {
+ $format = array_fill( 0, count( $children ), '%d' );
+ $query_in = '(' . implode( ',', $format ) . ')';
+ $prices = array_unique( $wpdb->get_col( $wpdb->prepare( "SELECT meta_value FROM $wpdb->postmeta WHERE meta_key = '_price' AND post_id IN {$query_in}", $children ) ) ); // @codingStandardsIgnoreLine.
+ } else {
+ $prices = array();
+ }
+
+ delete_post_meta( $product->get_id(), '_price' );
+ delete_post_meta( $product->get_id(), '_sale_price' );
+ delete_post_meta( $product->get_id(), '_regular_price' );
+
+ if ( $prices ) {
+ sort( $prices, SORT_NUMERIC );
+ // To allow sorting and filtering by multiple values, we have no choice but to store child prices in this manner.
+ foreach ( $prices as $price ) {
+ if ( is_null( $price ) || '' === $price ) {
+ continue;
+ }
+ add_post_meta( $product->get_id(), '_price', $price, false );
+ }
+ }
+
+ $this->update_lookup_table( $product->get_id(), 'wc_product_meta_lookup' );
+
+ /**
+ * Fire an action for this direct update so it can be detected by other code.
+ *
+ * @since 3.6
+ * @param int $product_id Product ID that was updated directly.
+ */
+ do_action( 'woocommerce_updated_product_price', $product->get_id() );
+ }
+
+ /**
+ * Sync variable product stock status with children.
+ * Change does not persist unless saved by caller.
+ *
+ * @param WC_Product $product Product object.
+ *
+ * @since 3.0.0
+ */
+ public function sync_stock_status( &$product ) {
+ if ( $product->child_is_in_stock() ) {
+ $product->set_stock_status( 'instock' );
+ } elseif ( $product->child_is_on_backorder() ) {
+ $product->set_stock_status( 'onbackorder' );
+ } else {
+ $product->set_stock_status( 'outofstock' );
+ }
+ }
+
+ /**
+ * Delete variations of a product.
+ *
+ * @param int $product_id Product ID.
+ * @param bool $force_delete False to trash.
+ *
+ * @since 3.0.0
+ */
+ public function delete_variations( $product_id, $force_delete = false ) {
+ if ( ! is_numeric( $product_id ) || 0 >= $product_id ) {
+ return;
+ }
+
+ $variation_ids = wp_parse_id_list(
+ get_posts(
+ array(
+ 'post_parent' => $product_id,
+ 'post_type' => 'product_variation',
+ 'fields' => 'ids',
+ 'post_status' => array( 'any', 'trash', 'auto-draft' ),
+ 'numberposts' => -1, // phpcs:ignore WordPress.VIP.PostsPerPage.posts_per_page_numberposts
+ )
+ )
+ );
+
+ if ( ! empty( $variation_ids ) ) {
+ foreach ( $variation_ids as $variation_id ) {
+ if ( $force_delete ) {
+ do_action( 'woocommerce_before_delete_product_variation', $variation_id );
+ wp_delete_post( $variation_id, true );
+ do_action( 'woocommerce_delete_product_variation', $variation_id );
+ } else {
+ wp_trash_post( $variation_id );
+ do_action( 'woocommerce_trash_product_variation', $variation_id );
+ }
+ }
+ }
+
+ delete_transient( 'wc_product_children_' . $product_id );
+ }
+
+ /**
+ * Untrash variations.
+ *
+ * @param int $product_id Product ID.
+ */
+ public function untrash_variations( $product_id ) {
+ $variation_ids = wp_parse_id_list(
+ get_posts(
+ array(
+ 'post_parent' => $product_id,
+ 'post_type' => 'product_variation',
+ 'fields' => 'ids',
+ 'post_status' => 'trash',
+ 'numberposts' => -1, // phpcs:ignore WordPress.VIP.PostsPerPage.posts_per_page_numberposts
+ )
+ )
+ );
+
+ if ( ! empty( $variation_ids ) ) {
+ foreach ( $variation_ids as $variation_id ) {
+ wp_untrash_post( $variation_id );
+ }
+ }
+
+ delete_transient( 'wc_product_children_' . $product_id );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-product-variation-data-store-cpt.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-product-variation-data-store-cpt.php
new file mode 100644
index 0000000..534ba38
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-product-variation-data-store-cpt.php
@@ -0,0 +1,547 @@
+meta_key, $this->internal_meta_keys, true ) && 0 !== stripos( $meta->meta_key, 'attribute_' ) && 0 !== stripos( $meta->meta_key, 'wp_' );
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | CRUD Methods
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Reads a product from the database and sets its data to the class.
+ *
+ * @since 3.0.0
+ * @param WC_Product_Variation $product Product object.
+ * @throws WC_Data_Exception If WC_Product::set_tax_status() is called with an invalid tax status (via read_product_data), or when passing an invalid ID.
+ */
+ public function read( &$product ) {
+ $product->set_defaults();
+
+ if ( ! $product->get_id() ) {
+ return;
+ }
+
+ $post_object = get_post( $product->get_id() );
+
+ if ( ! $post_object ) {
+ return;
+ }
+
+ if ( 'product_variation' !== $post_object->post_type ) {
+ throw new WC_Data_Exception( 'variation_invalid_id', __( 'Invalid product type: passed ID does not correspond to a product variation.', 'woocommerce' ) );
+ }
+
+ $product->set_props(
+ array(
+ 'name' => $post_object->post_title,
+ 'slug' => $post_object->post_name,
+ 'date_created' => $this->string_to_timestamp( $post_object->post_date_gmt ),
+ 'date_modified' => $this->string_to_timestamp( $post_object->post_modified_gmt ),
+ 'status' => $post_object->post_status,
+ 'menu_order' => $post_object->menu_order,
+ 'reviews_allowed' => 'open' === $post_object->comment_status,
+ 'parent_id' => $post_object->post_parent,
+ 'attribute_summary' => $post_object->post_excerpt,
+ )
+ );
+
+ // The post parent is not a valid variable product so we should prevent this.
+ if ( $product->get_parent_id( 'edit' ) && 'product' !== get_post_type( $product->get_parent_id( 'edit' ) ) ) {
+ $product->set_parent_id( 0 );
+ }
+
+ $this->read_downloads( $product );
+ $this->read_product_data( $product );
+ $this->read_extra_data( $product );
+ $product->set_attributes( wc_get_product_variation_attributes( $product->get_id() ) );
+
+ $updates = array();
+ /**
+ * If a variation title is not in sync with the parent e.g. saved prior to 3.0, or if the parent title has changed, detect here and update.
+ */
+ $new_title = $this->generate_product_title( $product );
+
+ if ( $post_object->post_title !== $new_title ) {
+ $product->set_name( $new_title );
+ $updates = array_merge( $updates, array( 'post_title' => $new_title ) );
+ }
+
+ /**
+ * If the attribute summary is not in sync, update here. Used when searching for variations by attribute values.
+ * This is meant to also cover the case when global attribute name or value is updated, then the attribute summary is updated
+ * for respective products when they're read.
+ */
+ $new_attribute_summary = $this->generate_attribute_summary( $product );
+
+ if ( $new_attribute_summary !== $post_object->post_excerpt ) {
+ $product->set_attribute_summary( $new_attribute_summary );
+ $updates = array_merge( $updates, array( 'post_excerpt' => $new_attribute_summary ) );
+ }
+
+ if ( ! empty( $updates ) ) {
+ $GLOBALS['wpdb']->update( $GLOBALS['wpdb']->posts, $updates, array( 'ID' => $product->get_id() ) );
+ clean_post_cache( $product->get_id() );
+ }
+
+ // Set object_read true once all data is read.
+ $product->set_object_read( true );
+ }
+
+ /**
+ * Create a new product.
+ *
+ * @since 3.0.0
+ * @param WC_Product_Variation $product Product object.
+ */
+ public function create( &$product ) {
+ if ( ! $product->get_date_created() ) {
+ $product->set_date_created( time() );
+ }
+
+ $new_title = $this->generate_product_title( $product );
+
+ if ( $product->get_name( 'edit' ) !== $new_title ) {
+ $product->set_name( $new_title );
+ }
+
+ $attribute_summary = $this->generate_attribute_summary( $product );
+ $product->set_attribute_summary( $attribute_summary );
+
+ // The post parent is not a valid variable product so we should prevent this.
+ if ( $product->get_parent_id( 'edit' ) && 'product' !== get_post_type( $product->get_parent_id( 'edit' ) ) ) {
+ $product->set_parent_id( 0 );
+ }
+
+ $id = wp_insert_post(
+ apply_filters(
+ 'woocommerce_new_product_variation_data',
+ array(
+ 'post_type' => 'product_variation',
+ 'post_status' => $product->get_status() ? $product->get_status() : 'publish',
+ 'post_author' => get_current_user_id(),
+ 'post_title' => $product->get_name( 'edit' ),
+ 'post_excerpt' => $product->get_attribute_summary( 'edit' ),
+ 'post_content' => '',
+ 'post_parent' => $product->get_parent_id(),
+ 'comment_status' => 'closed',
+ 'ping_status' => 'closed',
+ 'menu_order' => $product->get_menu_order(),
+ 'post_date' => gmdate( 'Y-m-d H:i:s', $product->get_date_created( 'edit' )->getOffsetTimestamp() ),
+ 'post_date_gmt' => gmdate( 'Y-m-d H:i:s', $product->get_date_created( 'edit' )->getTimestamp() ),
+ 'post_name' => $product->get_slug( 'edit' ),
+ )
+ ),
+ true
+ );
+
+ if ( $id && ! is_wp_error( $id ) ) {
+ $product->set_id( $id );
+
+ $this->update_post_meta( $product, true );
+ $this->update_terms( $product, true );
+ $this->update_visibility( $product, true );
+ $this->update_attributes( $product, true );
+ $this->handle_updated_props( $product );
+
+ $product->save_meta_data();
+ $product->apply_changes();
+
+ $this->update_version_and_type( $product );
+ $this->update_guid( $product );
+
+ $this->clear_caches( $product );
+
+ do_action( 'woocommerce_new_product_variation', $id, $product );
+ }
+ }
+
+ /**
+ * Updates an existing product.
+ *
+ * @since 3.0.0
+ * @param WC_Product_Variation $product Product object.
+ */
+ public function update( &$product ) {
+ $product->save_meta_data();
+
+ if ( ! $product->get_date_created() ) {
+ $product->set_date_created( time() );
+ }
+
+ $new_title = $this->generate_product_title( $product );
+
+ if ( $product->get_name( 'edit' ) !== $new_title ) {
+ $product->set_name( $new_title );
+ }
+
+ // The post parent is not a valid variable product so we should prevent this.
+ if ( $product->get_parent_id( 'edit' ) && 'product' !== get_post_type( $product->get_parent_id( 'edit' ) ) ) {
+ $product->set_parent_id( 0 );
+ }
+
+ $changes = $product->get_changes();
+
+ if ( array_intersect( array( 'attributes' ), array_keys( $changes ) ) ) {
+ $product->set_attribute_summary( $this->generate_attribute_summary( $product ) );
+ }
+
+ // Only update the post when the post data changes.
+ if ( array_intersect( array( 'name', 'parent_id', 'status', 'menu_order', 'date_created', 'date_modified', 'attributes' ), array_keys( $changes ) ) ) {
+ $post_data = array(
+ 'post_title' => $product->get_name( 'edit' ),
+ 'post_excerpt' => $product->get_attribute_summary( 'edit' ),
+ 'post_parent' => $product->get_parent_id( 'edit' ),
+ 'comment_status' => 'closed',
+ 'post_status' => $product->get_status( 'edit' ) ? $product->get_status( 'edit' ) : 'publish',
+ 'menu_order' => $product->get_menu_order( 'edit' ),
+ 'post_date' => gmdate( 'Y-m-d H:i:s', $product->get_date_created( 'edit' )->getOffsetTimestamp() ),
+ 'post_date_gmt' => gmdate( 'Y-m-d H:i:s', $product->get_date_created( 'edit' )->getTimestamp() ),
+ 'post_modified' => isset( $changes['date_modified'] ) ? gmdate( 'Y-m-d H:i:s', $product->get_date_modified( 'edit' )->getOffsetTimestamp() ) : current_time( 'mysql' ),
+ 'post_modified_gmt' => isset( $changes['date_modified'] ) ? gmdate( 'Y-m-d H:i:s', $product->get_date_modified( 'edit' )->getTimestamp() ) : current_time( 'mysql', 1 ),
+ 'post_type' => 'product_variation',
+ 'post_name' => $product->get_slug( 'edit' ),
+ );
+
+ /**
+ * When updating this object, to prevent infinite loops, use $wpdb
+ * to update data, since wp_update_post spawns more calls to the
+ * save_post action.
+ *
+ * This ensures hooks are fired by either WP itself (admin screen save),
+ * or an update purely from CRUD.
+ */
+ if ( doing_action( 'save_post' ) ) {
+ $GLOBALS['wpdb']->update( $GLOBALS['wpdb']->posts, $post_data, array( 'ID' => $product->get_id() ) );
+ clean_post_cache( $product->get_id() );
+ } else {
+ wp_update_post( array_merge( array( 'ID' => $product->get_id() ), $post_data ) );
+ }
+ $product->read_meta_data( true ); // Refresh internal meta data, in case things were hooked into `save_post` or another WP hook.
+
+ } else { // Only update post modified time to record this save event.
+ $GLOBALS['wpdb']->update(
+ $GLOBALS['wpdb']->posts,
+ array(
+ 'post_modified' => current_time( 'mysql' ),
+ 'post_modified_gmt' => current_time( 'mysql', 1 ),
+ ),
+ array(
+ 'ID' => $product->get_id(),
+ )
+ );
+ clean_post_cache( $product->get_id() );
+ }
+
+ $this->update_post_meta( $product );
+ $this->update_terms( $product );
+ $this->update_visibility( $product, true );
+ $this->update_attributes( $product );
+ $this->handle_updated_props( $product );
+
+ $product->apply_changes();
+
+ $this->update_version_and_type( $product );
+
+ $this->clear_caches( $product );
+
+ do_action( 'woocommerce_update_product_variation', $product->get_id(), $product );
+ }
+
+ /*
+ |--------------------------------------------------------------------------
+ | Additional Methods
+ |--------------------------------------------------------------------------
+ */
+
+ /**
+ * Generates a title with attribute information for a variation.
+ * Products will get a title of the form "Name - Value, Value" or just "Name".
+ *
+ * @since 3.0.0
+ * @param WC_Product $product Product object.
+ * @return string
+ */
+ protected function generate_product_title( $product ) {
+ $attributes = (array) $product->get_attributes();
+
+ // Do not include attributes if the product has 3+ attributes.
+ $should_include_attributes = count( $attributes ) < 3;
+
+ // Do not include attributes if an attribute name has 2+ words and the
+ // product has multiple attributes.
+ if ( $should_include_attributes && 1 < count( $attributes ) ) {
+ foreach ( $attributes as $name => $value ) {
+ if ( false !== strpos( $name, '-' ) ) {
+ $should_include_attributes = false;
+ break;
+ }
+ }
+ }
+
+ $should_include_attributes = apply_filters( 'woocommerce_product_variation_title_include_attributes', $should_include_attributes, $product );
+ $separator = apply_filters( 'woocommerce_product_variation_title_attributes_separator', ' - ', $product );
+ $title_base = get_post_field( 'post_title', $product->get_parent_id() );
+ $title_suffix = $should_include_attributes ? wc_get_formatted_variation( $product, true, false ) : '';
+
+ return apply_filters( 'woocommerce_product_variation_title', $title_suffix ? $title_base . $separator . $title_suffix : $title_base, $product, $title_base, $title_suffix );
+ }
+
+ /**
+ * Generates attribute summary for the variation.
+ *
+ * Attribute summary contains comma-delimited 'attribute_name: attribute_value' pairs for all attributes.
+ *
+ * @since 3.6.0
+ * @param WC_Product_Variation $product Product variation to generate the attribute summary for.
+ *
+ * @return string
+ */
+ protected function generate_attribute_summary( $product ) {
+ return wc_get_formatted_variation( $product, true, true );
+ }
+
+ /**
+ * Make sure we store the product version (to track data changes).
+ *
+ * @param WC_Product $product Product object.
+ * @since 3.0.0
+ */
+ protected function update_version_and_type( &$product ) {
+ wp_set_object_terms( $product->get_id(), '', 'product_type' );
+ update_post_meta( $product->get_id(), '_product_version', Constants::get_constant( 'WC_VERSION' ) );
+ }
+
+ /**
+ * Read post data.
+ *
+ * @since 3.0.0
+ * @param WC_Product_Variation $product Product object.
+ * @throws WC_Data_Exception If WC_Product::set_tax_status() is called with an invalid tax status.
+ */
+ protected function read_product_data( &$product ) {
+ $id = $product->get_id();
+
+ $product->set_props(
+ array(
+ 'description' => get_post_meta( $id, '_variation_description', true ),
+ 'regular_price' => get_post_meta( $id, '_regular_price', true ),
+ 'sale_price' => get_post_meta( $id, '_sale_price', true ),
+ 'date_on_sale_from' => get_post_meta( $id, '_sale_price_dates_from', true ),
+ 'date_on_sale_to' => get_post_meta( $id, '_sale_price_dates_to', true ),
+ 'manage_stock' => get_post_meta( $id, '_manage_stock', true ),
+ 'stock_status' => get_post_meta( $id, '_stock_status', true ),
+ 'shipping_class_id' => current( $this->get_term_ids( $id, 'product_shipping_class' ) ),
+ 'virtual' => get_post_meta( $id, '_virtual', true ),
+ 'downloadable' => get_post_meta( $id, '_downloadable', true ),
+ 'gallery_image_ids' => array_filter( explode( ',', get_post_meta( $id, '_product_image_gallery', true ) ) ),
+ 'download_limit' => get_post_meta( $id, '_download_limit', true ),
+ 'download_expiry' => get_post_meta( $id, '_download_expiry', true ),
+ 'image_id' => get_post_thumbnail_id( $id ),
+ 'backorders' => get_post_meta( $id, '_backorders', true ),
+ 'sku' => get_post_meta( $id, '_sku', true ),
+ 'stock_quantity' => get_post_meta( $id, '_stock', true ),
+ 'weight' => get_post_meta( $id, '_weight', true ),
+ 'length' => get_post_meta( $id, '_length', true ),
+ 'width' => get_post_meta( $id, '_width', true ),
+ 'height' => get_post_meta( $id, '_height', true ),
+ 'tax_class' => ! metadata_exists( 'post', $id, '_tax_class' ) ? 'parent' : get_post_meta( $id, '_tax_class', true ),
+ )
+ );
+
+ if ( $product->is_on_sale( 'edit' ) ) {
+ $product->set_price( $product->get_sale_price( 'edit' ) );
+ } else {
+ $product->set_price( $product->get_regular_price( 'edit' ) );
+ }
+
+ $parent_object = get_post( $product->get_parent_id() );
+ $terms = get_the_terms( $product->get_parent_id(), 'product_visibility' );
+ $term_names = is_array( $terms ) ? wp_list_pluck( $terms, 'name' ) : array();
+ $exclude_search = in_array( 'exclude-from-search', $term_names, true );
+ $exclude_catalog = in_array( 'exclude-from-catalog', $term_names, true );
+
+ if ( $exclude_search && $exclude_catalog ) {
+ $catalog_visibility = 'hidden';
+ } elseif ( $exclude_search ) {
+ $catalog_visibility = 'catalog';
+ } elseif ( $exclude_catalog ) {
+ $catalog_visibility = 'search';
+ } else {
+ $catalog_visibility = 'visible';
+ }
+
+ $product->set_parent_data(
+ array(
+ 'title' => $parent_object ? $parent_object->post_title : '',
+ 'status' => $parent_object ? $parent_object->post_status : '',
+ 'sku' => get_post_meta( $product->get_parent_id(), '_sku', true ),
+ 'manage_stock' => get_post_meta( $product->get_parent_id(), '_manage_stock', true ),
+ 'backorders' => get_post_meta( $product->get_parent_id(), '_backorders', true ),
+ 'low_stock_amount' => get_post_meta( $product->get_parent_id(), '_low_stock_amount', true ),
+ 'stock_quantity' => wc_stock_amount( get_post_meta( $product->get_parent_id(), '_stock', true ) ),
+ 'weight' => get_post_meta( $product->get_parent_id(), '_weight', true ),
+ 'length' => get_post_meta( $product->get_parent_id(), '_length', true ),
+ 'width' => get_post_meta( $product->get_parent_id(), '_width', true ),
+ 'height' => get_post_meta( $product->get_parent_id(), '_height', true ),
+ 'tax_class' => get_post_meta( $product->get_parent_id(), '_tax_class', true ),
+ 'shipping_class_id' => absint( current( $this->get_term_ids( $product->get_parent_id(), 'product_shipping_class' ) ) ),
+ 'image_id' => get_post_thumbnail_id( $product->get_parent_id() ),
+ 'purchase_note' => get_post_meta( $product->get_parent_id(), '_purchase_note', true ),
+ 'catalog_visibility' => $catalog_visibility,
+ )
+ );
+
+ // Pull data from the parent when there is no user-facing way to set props.
+ $product->set_sold_individually( get_post_meta( $product->get_parent_id(), '_sold_individually', true ) );
+ $product->set_tax_status( get_post_meta( $product->get_parent_id(), '_tax_status', true ) );
+ $product->set_cross_sell_ids( get_post_meta( $product->get_parent_id(), '_crosssell_ids', true ) );
+ }
+
+ /**
+ * For all stored terms in all taxonomies, save them to the DB.
+ *
+ * @since 3.0.0
+ * @param WC_Product $product Product object.
+ * @param bool $force Force update. Used during create.
+ */
+ protected function update_terms( &$product, $force = false ) {
+ $changes = $product->get_changes();
+
+ if ( $force || array_key_exists( 'shipping_class_id', $changes ) ) {
+ wp_set_post_terms( $product->get_id(), array( $product->get_shipping_class_id( 'edit' ) ), 'product_shipping_class', false );
+ }
+ }
+
+ /**
+ * Update visibility terms based on props.
+ *
+ * @since 3.0.0
+ *
+ * @param WC_Product $product Product object.
+ * @param bool $force Force update. Used during create.
+ */
+ protected function update_visibility( &$product, $force = false ) {
+ $changes = $product->get_changes();
+
+ if ( $force || array_intersect( array( 'stock_status' ), array_keys( $changes ) ) ) {
+ $terms = array();
+
+ if ( 'outofstock' === $product->get_stock_status() ) {
+ $terms[] = 'outofstock';
+ }
+
+ wp_set_post_terms( $product->get_id(), $terms, 'product_visibility', false );
+ }
+ }
+
+ /**
+ * Update attribute meta values.
+ *
+ * @since 3.0.0
+ * @param WC_Product $product Product object.
+ * @param bool $force Force update. Used during create.
+ */
+ protected function update_attributes( &$product, $force = false ) {
+ $changes = $product->get_changes();
+
+ if ( $force || array_key_exists( 'attributes', $changes ) ) {
+ global $wpdb;
+
+ $product_id = $product->get_id();
+ $attributes = $product->get_attributes();
+ $updated_attribute_keys = array();
+ foreach ( $attributes as $key => $value ) {
+ update_post_meta( $product_id, 'attribute_' . $key, wp_slash( $value ) );
+ $updated_attribute_keys[] = 'attribute_' . $key;
+ }
+
+ // Remove old taxonomies attributes so data is kept up to date - first get attribute key names.
+ $delete_attribute_keys = $wpdb->get_col(
+ $wpdb->prepare(
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.QuotedDynamicPlaceholderGeneration
+ "SELECT meta_key FROM {$wpdb->postmeta} WHERE meta_key LIKE %s AND meta_key NOT IN ( '" . implode( "','", array_map( 'esc_sql', $updated_attribute_keys ) ) . "' ) AND post_id = %d",
+ $wpdb->esc_like( 'attribute_' ) . '%',
+ $product_id
+ )
+ );
+
+ foreach ( $delete_attribute_keys as $key ) {
+ delete_post_meta( $product_id, $key );
+ }
+ }
+ }
+
+ /**
+ * Helper method that updates all the post meta for a product based on it's settings in the WC_Product class.
+ *
+ * @since 3.0.0
+ * @param WC_Product $product Product object.
+ * @param bool $force Force update. Used during create.
+ */
+ public function update_post_meta( &$product, $force = false ) {
+ $meta_key_to_props = array(
+ '_variation_description' => 'description',
+ );
+
+ $props_to_update = $force ? $meta_key_to_props : $this->get_props_to_update( $product, $meta_key_to_props );
+
+ foreach ( $props_to_update as $meta_key => $prop ) {
+ $value = $product->{"get_$prop"}( 'edit' );
+ $updated = update_post_meta( $product->get_id(), $meta_key, $value );
+ if ( $updated ) {
+ $this->updated_props[] = $prop;
+ }
+ }
+
+ parent::update_post_meta( $product, $force );
+ }
+
+ /**
+ * Update product variation guid.
+ *
+ * @param WC_Product_Variation $product Product variation object.
+ *
+ * @since 3.6.0
+ */
+ protected function update_guid( $product ) {
+ global $wpdb;
+
+ $guid = home_url(
+ add_query_arg(
+ array(
+ 'post_type' => 'product_variation',
+ 'p' => $product->get_id(),
+ ),
+ ''
+ )
+ );
+ $wpdb->update( $wpdb->posts, array( 'guid' => $guid ), array( 'ID' => $product->get_id() ) );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-shipping-zone-data-store.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-shipping-zone-data-store.php
new file mode 100644
index 0000000..453ec87
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-shipping-zone-data-store.php
@@ -0,0 +1,365 @@
+insert(
+ $wpdb->prefix . 'woocommerce_shipping_zones',
+ array(
+ 'zone_name' => $zone->get_zone_name(),
+ 'zone_order' => $zone->get_zone_order(),
+ )
+ );
+ $zone->set_id( $wpdb->insert_id );
+ $zone->save_meta_data();
+ $this->save_locations( $zone );
+ $zone->apply_changes();
+ WC_Cache_Helper::invalidate_cache_group( 'shipping_zones' );
+ WC_Cache_Helper::get_transient_version( 'shipping', true );
+ }
+
+ /**
+ * Update zone in the database.
+ *
+ * @since 3.0.0
+ * @param WC_Shipping_Zone $zone Shipping zone object.
+ */
+ public function update( &$zone ) {
+ global $wpdb;
+ if ( $zone->get_id() ) {
+ $wpdb->update(
+ $wpdb->prefix . 'woocommerce_shipping_zones',
+ array(
+ 'zone_name' => $zone->get_zone_name(),
+ 'zone_order' => $zone->get_zone_order(),
+ ),
+ array( 'zone_id' => $zone->get_id() )
+ );
+ }
+ $zone->save_meta_data();
+ $this->save_locations( $zone );
+ $zone->apply_changes();
+ WC_Cache_Helper::invalidate_cache_group( 'shipping_zones' );
+ WC_Cache_Helper::get_transient_version( 'shipping', true );
+ }
+
+ /**
+ * Method to read a shipping zone from the database.
+ *
+ * @since 3.0.0
+ * @param WC_Shipping_Zone $zone Shipping zone object.
+ * @throws Exception If invalid data store.
+ */
+ public function read( &$zone ) {
+ global $wpdb;
+
+ $zone_data = false;
+
+ if ( 0 !== $zone->get_id() || '0' !== $zone->get_id() ) {
+ $zone_data = $wpdb->get_row(
+ $wpdb->prepare(
+ "SELECT zone_name, zone_order FROM {$wpdb->prefix}woocommerce_shipping_zones WHERE zone_id = %d LIMIT 1",
+ $zone->get_id()
+ )
+ );
+ }
+
+ if ( 0 === $zone->get_id() || '0' === $zone->get_id() ) {
+ $this->read_zone_locations( $zone );
+ $zone->set_zone_name( __( 'Locations not covered by your other zones', 'woocommerce' ) );
+ $zone->read_meta_data();
+ $zone->set_object_read( true );
+ do_action( 'woocommerce_shipping_zone_loaded', $zone );
+ } elseif ( $zone_data ) {
+ $zone->set_zone_name( $zone_data->zone_name );
+ $zone->set_zone_order( $zone_data->zone_order );
+ $this->read_zone_locations( $zone );
+ $zone->read_meta_data();
+ $zone->set_object_read( true );
+ do_action( 'woocommerce_shipping_zone_loaded', $zone );
+ } else {
+ throw new Exception( __( 'Invalid data store.', 'woocommerce' ) );
+ }
+ }
+
+ /**
+ * Deletes a shipping zone from the database.
+ *
+ * @since 3.0.0
+ * @param WC_Shipping_Zone $zone Shipping zone object.
+ * @param array $args Array of args to pass to the delete method.
+ * @return void
+ */
+ public function delete( &$zone, $args = array() ) {
+ $zone_id = $zone->get_id();
+
+ if ( $zone_id ) {
+ global $wpdb;
+
+ // Delete methods and their settings.
+ $methods = $this->get_methods( $zone_id, false );
+
+ if ( $methods ) {
+ foreach ( $methods as $method ) {
+ $this->delete_method( $method->instance_id );
+ }
+ }
+
+ // Delete zone.
+ $wpdb->delete( $wpdb->prefix . 'woocommerce_shipping_zone_locations', array( 'zone_id' => $zone_id ) );
+ $wpdb->delete( $wpdb->prefix . 'woocommerce_shipping_zones', array( 'zone_id' => $zone_id ) );
+
+ $zone->set_id( null );
+
+ WC_Cache_Helper::invalidate_cache_group( 'shipping_zones' );
+ WC_Cache_Helper::get_transient_version( 'shipping', true );
+
+ do_action( 'woocommerce_delete_shipping_zone', $zone_id );
+ }
+ }
+
+ /**
+ * Get a list of shipping methods for a specific zone.
+ *
+ * @since 3.0.0
+ * @param int $zone_id Zone ID.
+ * @param bool $enabled_only True to request enabled methods only.
+ * @return array Array of objects containing method_id, method_order, instance_id, is_enabled
+ */
+ public function get_methods( $zone_id, $enabled_only ) {
+ global $wpdb;
+
+ if ( $enabled_only ) {
+ $raw_methods_sql = "SELECT method_id, method_order, instance_id, is_enabled FROM {$wpdb->prefix}woocommerce_shipping_zone_methods WHERE zone_id = %d AND is_enabled = 1";
+ } else {
+ $raw_methods_sql = "SELECT method_id, method_order, instance_id, is_enabled FROM {$wpdb->prefix}woocommerce_shipping_zone_methods WHERE zone_id = %d";
+ }
+
+ return $wpdb->get_results( $wpdb->prepare( $raw_methods_sql, $zone_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
+ }
+
+ /**
+ * Get count of methods for a zone.
+ *
+ * @since 3.0.0
+ * @param int $zone_id Zone ID.
+ * @return int Method Count
+ */
+ public function get_method_count( $zone_id ) {
+ global $wpdb;
+ return $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->prefix}woocommerce_shipping_zone_methods WHERE zone_id = %d", $zone_id ) );
+ }
+
+ /**
+ * Add a shipping method to a zone.
+ *
+ * @since 3.0.0
+ * @param int $zone_id Zone ID.
+ * @param string $type Method Type/ID.
+ * @param int $order Method Order.
+ * @return int Instance ID
+ */
+ public function add_method( $zone_id, $type, $order ) {
+ global $wpdb;
+ $wpdb->insert(
+ $wpdb->prefix . 'woocommerce_shipping_zone_methods',
+ array(
+ 'method_id' => $type,
+ 'zone_id' => $zone_id,
+ 'method_order' => $order,
+ ),
+ array(
+ '%s',
+ '%d',
+ '%d',
+ )
+ );
+ return $wpdb->insert_id;
+ }
+
+ /**
+ * Delete a method instance.
+ *
+ * @since 3.0.0
+ * @param int $instance_id Instance ID.
+ */
+ public function delete_method( $instance_id ) {
+ global $wpdb;
+
+ $method = $this->get_method( $instance_id );
+
+ if ( ! $method ) {
+ return;
+ }
+
+ delete_option( 'woocommerce_' . $method->method_id . '_' . $instance_id . '_settings' );
+
+ $wpdb->delete( $wpdb->prefix . 'woocommerce_shipping_zone_methods', array( 'instance_id' => $instance_id ) );
+
+ do_action( 'woocommerce_delete_shipping_zone_method', $instance_id );
+ }
+
+ /**
+ * Get a shipping zone method instance.
+ *
+ * @since 3.0.0
+ * @param int $instance_id Instance ID.
+ * @return object
+ */
+ public function get_method( $instance_id ) {
+ global $wpdb;
+ return $wpdb->get_row( $wpdb->prepare( "SELECT zone_id, method_id, instance_id, method_order, is_enabled FROM {$wpdb->prefix}woocommerce_shipping_zone_methods WHERE instance_id = %d LIMIT 1;", $instance_id ) );
+ }
+
+ /**
+ * Find a matching zone ID for a given package.
+ *
+ * @since 3.0.0
+ * @param object $package Package information.
+ * @return int
+ */
+ public function get_zone_id_from_package( $package ) {
+ global $wpdb;
+
+ $country = strtoupper( wc_clean( $package['destination']['country'] ) );
+ $state = strtoupper( wc_clean( $package['destination']['state'] ) );
+ $continent = strtoupper( wc_clean( WC()->countries->get_continent_code_for_country( $country ) ) );
+ $postcode = wc_normalize_postcode( wc_clean( $package['destination']['postcode'] ) );
+
+ // Work out criteria for our zone search.
+ $criteria = array();
+ $criteria[] = $wpdb->prepare( "( ( location_type = 'country' AND location_code = %s )", $country );
+ $criteria[] = $wpdb->prepare( "OR ( location_type = 'state' AND location_code = %s )", $country . ':' . $state );
+ $criteria[] = $wpdb->prepare( "OR ( location_type = 'continent' AND location_code = %s )", $continent );
+ $criteria[] = 'OR ( location_type IS NULL ) )';
+
+ // Postcode range and wildcard matching.
+ $postcode_locations = $wpdb->get_results( "SELECT zone_id, location_code FROM {$wpdb->prefix}woocommerce_shipping_zone_locations WHERE location_type = 'postcode';" );
+
+ if ( $postcode_locations ) {
+ $zone_ids_with_postcode_rules = array_map( 'absint', wp_list_pluck( $postcode_locations, 'zone_id' ) );
+ $matches = wc_postcode_location_matcher( $postcode, $postcode_locations, 'zone_id', 'location_code', $country );
+ $do_not_match = array_unique( array_diff( $zone_ids_with_postcode_rules, array_keys( $matches ) ) );
+
+ if ( ! empty( $do_not_match ) ) {
+ $criteria[] = 'AND zones.zone_id NOT IN (' . implode( ',', $do_not_match ) . ')';
+ }
+ }
+
+ /**
+ * Get shipping zone criteria
+ *
+ * @since 3.6.6
+ * @param array $criteria Get zone criteria.
+ * @param array $package Package information.
+ * @param array $postcode_locations Postcode range and wildcard matching.
+ */
+ $criteria = apply_filters( 'woocommerce_get_zone_criteria', $criteria, $package, $postcode_locations );
+
+ // Get matching zones.
+ return $wpdb->get_var(
+ "SELECT zones.zone_id FROM {$wpdb->prefix}woocommerce_shipping_zones as zones
+ LEFT OUTER JOIN {$wpdb->prefix}woocommerce_shipping_zone_locations as locations ON zones.zone_id = locations.zone_id AND location_type != 'postcode'
+ WHERE " . implode( ' ', $criteria ) // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
+ . ' ORDER BY zone_order ASC, zones.zone_id ASC LIMIT 1'
+ );
+ }
+
+ /**
+ * Return an ordered list of zones.
+ *
+ * @since 3.0.0
+ * @return array An array of objects containing a zone_id, zone_name, and zone_order.
+ */
+ public function get_zones() {
+ global $wpdb;
+ return $wpdb->get_results( "SELECT zone_id, zone_name, zone_order FROM {$wpdb->prefix}woocommerce_shipping_zones order by zone_order ASC, zone_id ASC;" );
+ }
+
+
+ /**
+ * Return a zone ID from an instance ID.
+ *
+ * @since 3.0.0
+ * @param int $id Instnace ID.
+ * @return int
+ */
+ public function get_zone_id_by_instance_id( $id ) {
+ global $wpdb;
+ return $wpdb->get_var( $wpdb->prepare( "SELECT zone_id FROM {$wpdb->prefix}woocommerce_shipping_zone_methods as methods WHERE methods.instance_id = %d LIMIT 1;", $id ) );
+ }
+
+ /**
+ * Read location data from the database.
+ *
+ * @param WC_Shipping_Zone $zone Shipping zone object.
+ */
+ private function read_zone_locations( &$zone ) {
+ global $wpdb;
+
+ $locations = $wpdb->get_results(
+ $wpdb->prepare(
+ "SELECT location_code, location_type FROM {$wpdb->prefix}woocommerce_shipping_zone_locations WHERE zone_id = %d",
+ $zone->get_id()
+ )
+ );
+
+ if ( $locations ) {
+ foreach ( $locations as $location ) {
+ $zone->add_location( $location->location_code, $location->location_type );
+ }
+ }
+ }
+
+ /**
+ * Save locations to the DB.
+ * This function clears old locations, then re-inserts new if any changes are found.
+ *
+ * @since 3.0.0
+ *
+ * @param WC_Shipping_Zone $zone Shipping zone object.
+ *
+ * @return bool|void
+ */
+ private function save_locations( &$zone ) {
+ $changed_props = array_keys( $zone->get_changes() );
+ if ( ! in_array( 'zone_locations', $changed_props, true ) ) {
+ return false;
+ }
+
+ global $wpdb;
+ $wpdb->delete( $wpdb->prefix . 'woocommerce_shipping_zone_locations', array( 'zone_id' => $zone->get_id() ) );
+
+ foreach ( $zone->get_zone_locations( 'edit' ) as $location ) {
+ $wpdb->insert(
+ $wpdb->prefix . 'woocommerce_shipping_zone_locations',
+ array(
+ 'zone_id' => $zone->get_id(),
+ 'location_code' => $location->code,
+ 'location_type' => $location->type,
+ )
+ );
+ }
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-webhook-data-store.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-webhook-data-store.php
new file mode 100644
index 0000000..947e89e
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/data-stores/class-wc-webhook-data-store.php
@@ -0,0 +1,447 @@
+get_changes();
+ if ( isset( $changes['date_created'] ) ) {
+ $date_created = $webhook->get_date_created()->date( 'Y-m-d H:i:s' );
+ $date_created_gmt = gmdate( 'Y-m-d H:i:s', $webhook->get_date_created()->getTimestamp() );
+ } else {
+ $date_created = current_time( 'mysql' );
+ $date_created_gmt = current_time( 'mysql', 1 );
+ $webhook->set_date_created( $date_created );
+ }
+
+ // Pending delivery by default if not set while creating a new webhook.
+ if ( ! isset( $changes['pending_delivery'] ) ) {
+ $webhook->set_pending_delivery( true );
+ }
+
+ $data = array(
+ 'status' => $webhook->get_status( 'edit' ),
+ 'name' => $webhook->get_name( 'edit' ),
+ 'user_id' => $webhook->get_user_id( 'edit' ),
+ 'delivery_url' => $webhook->get_delivery_url( 'edit' ),
+ 'secret' => $webhook->get_secret( 'edit' ),
+ 'topic' => $webhook->get_topic( 'edit' ),
+ 'date_created' => $date_created,
+ 'date_created_gmt' => $date_created_gmt,
+ 'api_version' => $this->get_api_version_number( $webhook->get_api_version( 'edit' ) ),
+ 'failure_count' => $webhook->get_failure_count( 'edit' ),
+ 'pending_delivery' => $webhook->get_pending_delivery( 'edit' ),
+ );
+
+ $wpdb->insert( $wpdb->prefix . 'wc_webhooks', $data ); // WPCS: DB call ok.
+
+ $webhook_id = $wpdb->insert_id;
+ $webhook->set_id( $webhook_id );
+ $webhook->apply_changes();
+
+ $this->delete_transients( $webhook->get_status( 'edit' ) );
+ WC_Cache_Helper::invalidate_cache_group( 'webhooks' );
+ do_action( 'woocommerce_new_webhook', $webhook_id, $webhook );
+ }
+
+ /**
+ * Read a webhook from the database.
+ *
+ * @since 3.3.0
+ * @param WC_Webhook $webhook Webhook instance.
+ * @throws Exception When webhook is invalid.
+ */
+ public function read( &$webhook ) {
+ global $wpdb;
+
+ $data = wp_cache_get( $webhook->get_id(), 'webhooks' );
+
+ if ( false === $data ) {
+ $data = $wpdb->get_row( $wpdb->prepare( "SELECT webhook_id, status, name, user_id, delivery_url, secret, topic, date_created, date_modified, api_version, failure_count, pending_delivery FROM {$wpdb->prefix}wc_webhooks WHERE webhook_id = %d LIMIT 1;", $webhook->get_id() ), ARRAY_A ); // WPCS: cache ok, DB call ok.
+
+ wp_cache_add( $webhook->get_id(), $data, 'webhooks' );
+ }
+
+ if ( is_array( $data ) ) {
+ $webhook->set_props(
+ array(
+ 'id' => $data['webhook_id'],
+ 'status' => $data['status'],
+ 'name' => $data['name'],
+ 'user_id' => $data['user_id'],
+ 'delivery_url' => $data['delivery_url'],
+ 'secret' => $data['secret'],
+ 'topic' => $data['topic'],
+ 'date_created' => '0000-00-00 00:00:00' === $data['date_created'] ? null : $data['date_created'],
+ 'date_modified' => '0000-00-00 00:00:00' === $data['date_modified'] ? null : $data['date_modified'],
+ 'api_version' => $data['api_version'],
+ 'failure_count' => $data['failure_count'],
+ 'pending_delivery' => $data['pending_delivery'],
+ )
+ );
+ $webhook->set_object_read( true );
+
+ do_action( 'woocommerce_webhook_loaded', $webhook );
+ } else {
+ throw new Exception( __( 'Invalid webhook.', 'woocommerce' ) );
+ }
+ }
+
+ /**
+ * Update a webhook.
+ *
+ * @since 3.3.0
+ * @param WC_Webhook $webhook Webhook instance.
+ */
+ public function update( &$webhook ) {
+ global $wpdb;
+
+ $changes = $webhook->get_changes();
+ $trigger = isset( $changes['delivery_url'] );
+
+ if ( isset( $changes['date_modified'] ) ) {
+ $date_modified = $webhook->get_date_modified()->date( 'Y-m-d H:i:s' );
+ $date_modified_gmt = gmdate( 'Y-m-d H:i:s', $webhook->get_date_modified()->getTimestamp() );
+ } else {
+ $date_modified = current_time( 'mysql' );
+ $date_modified_gmt = current_time( 'mysql', 1 );
+ $webhook->set_date_modified( $date_modified );
+ }
+
+ $data = array(
+ 'status' => $webhook->get_status( 'edit' ),
+ 'name' => $webhook->get_name( 'edit' ),
+ 'user_id' => $webhook->get_user_id( 'edit' ),
+ 'delivery_url' => $webhook->get_delivery_url( 'edit' ),
+ 'secret' => $webhook->get_secret( 'edit' ),
+ 'topic' => $webhook->get_topic( 'edit' ),
+ 'date_modified' => $date_modified,
+ 'date_modified_gmt' => $date_modified_gmt,
+ 'api_version' => $this->get_api_version_number( $webhook->get_api_version( 'edit' ) ),
+ 'failure_count' => $webhook->get_failure_count( 'edit' ),
+ 'pending_delivery' => $webhook->get_pending_delivery( 'edit' ),
+ );
+
+ $wpdb->update(
+ $wpdb->prefix . 'wc_webhooks',
+ $data,
+ array(
+ 'webhook_id' => $webhook->get_id(),
+ )
+ ); // WPCS: DB call ok.
+
+ $webhook->apply_changes();
+
+ if ( isset( $changes['status'] ) ) {
+ // We need to delete all transients, because we can't be sure of the old status.
+ $this->delete_transients( 'all' );
+ }
+ wp_cache_delete( $webhook->get_id(), 'webhooks' );
+ WC_Cache_Helper::invalidate_cache_group( 'webhooks' );
+
+ if ( 'active' === $webhook->get_status() && ( $trigger || $webhook->get_pending_delivery() ) ) {
+ $webhook->deliver_ping();
+ }
+
+ do_action( 'woocommerce_webhook_updated', $webhook->get_id() );
+ }
+
+ /**
+ * Remove a webhook from the database.
+ *
+ * @since 3.3.0
+ * @param WC_Webhook $webhook Webhook instance.
+ */
+ public function delete( &$webhook ) {
+ global $wpdb;
+
+ $wpdb->delete(
+ $wpdb->prefix . 'wc_webhooks',
+ array(
+ 'webhook_id' => $webhook->get_id(),
+ ),
+ array( '%d' )
+ ); // WPCS: cache ok, DB call ok.
+
+ $this->delete_transients( 'all' );
+ wp_cache_delete( $webhook->get_id(), 'webhooks' );
+ WC_Cache_Helper::invalidate_cache_group( 'webhooks' );
+ do_action( 'woocommerce_webhook_deleted', $webhook->get_id(), $webhook );
+ }
+
+ /**
+ * Get API version number.
+ *
+ * @since 3.3.0
+ * @param string $api_version REST API version.
+ * @return int
+ */
+ public function get_api_version_number( $api_version ) {
+ return 'legacy_v3' === $api_version ? -1 : intval( substr( $api_version, -1 ) );
+ }
+
+ /**
+ * Get webhooks IDs from the database.
+ *
+ * @since 3.3.0
+ * @throws InvalidArgumentException If a $status value is passed in that is not in the known wc_get_webhook_statuses() keys.
+ * @param string $status Optional - status to filter results by. Must be a key in return value of @see wc_get_webhook_statuses(). @since 3.6.0.
+ * @return int[]
+ */
+ public function get_webhooks_ids( $status = '' ) {
+ if ( ! empty( $status ) ) {
+ $this->validate_status( $status );
+ }
+
+ $ids = get_transient( $this->get_transient_key( $status ) );
+
+ if ( false === $ids ) {
+ $ids = $this->search_webhooks(
+ array(
+ 'limit' => -1,
+ 'status' => $status,
+ )
+ );
+ $ids = array_map( 'absint', $ids );
+ set_transient( $this->get_transient_key( $status ), $ids );
+ }
+
+ return $ids;
+ }
+
+ /**
+ * Search webhooks.
+ *
+ * @param array $args Search arguments.
+ * @return array|object
+ */
+ public function search_webhooks( $args ) {
+ global $wpdb;
+
+ $args = wp_parse_args(
+ $args,
+ array(
+ 'limit' => 10,
+ 'offset' => 0,
+ 'order' => 'DESC',
+ 'orderby' => 'id',
+ 'paginate' => false,
+ )
+ );
+
+ // Map post statuses.
+ $statuses = array(
+ 'publish' => 'active',
+ 'draft' => 'paused',
+ 'pending' => 'disabled',
+ );
+
+ // Map orderby to support a few post keys.
+ $orderby_mapping = array(
+ 'ID' => 'webhook_id',
+ 'id' => 'webhook_id',
+ 'name' => 'name',
+ 'title' => 'name',
+ 'post_title' => 'name',
+ 'post_name' => 'name',
+ 'date_created' => 'date_created_gmt',
+ 'date' => 'date_created_gmt',
+ 'post_date' => 'date_created_gmt',
+ 'date_modified' => 'date_modified_gmt',
+ 'modified' => 'date_modified_gmt',
+ 'post_modified' => 'date_modified_gmt',
+ );
+ $orderby = isset( $orderby_mapping[ $args['orderby'] ] ) ? $orderby_mapping[ $args['orderby'] ] : 'webhook_id';
+ $order = "ORDER BY {$orderby} " . esc_sql( strtoupper( $args['order'] ) );
+ $limit = -1 < $args['limit'] ? $wpdb->prepare( 'LIMIT %d', $args['limit'] ) : '';
+ $offset = 0 < $args['offset'] ? $wpdb->prepare( 'OFFSET %d', $args['offset'] ) : '';
+ $status = ! empty( $args['status'] ) ? $wpdb->prepare( 'AND `status` = %s', isset( $statuses[ $args['status'] ] ) ? $statuses[ $args['status'] ] : $args['status'] ) : '';
+ $search = ! empty( $args['search'] ) ? "AND `name` LIKE '%" . $wpdb->esc_like( sanitize_text_field( $args['search'] ) ) . "%'" : '';
+ $include = '';
+ $exclude = '';
+ $date_created = '';
+ $date_modified = '';
+
+ if ( ! empty( $args['include'] ) ) {
+ $args['include'] = implode( ',', wp_parse_id_list( $args['include'] ) );
+ $include = 'AND webhook_id IN (' . $args['include'] . ')';
+ }
+
+ if ( ! empty( $args['exclude'] ) ) {
+ $args['exclude'] = implode( ',', wp_parse_id_list( $args['exclude'] ) );
+ $exclude = 'AND webhook_id NOT IN (' . $args['exclude'] . ')';
+ }
+
+ if ( ! empty( $args['after'] ) || ! empty( $args['before'] ) ) {
+ $args['after'] = empty( $args['after'] ) ? '0000-00-00' : $args['after'];
+ $args['before'] = empty( $args['before'] ) ? current_time( 'mysql', 1 ) : $args['before'];
+
+ $date_created = "AND `date_created_gmt` BETWEEN STR_TO_DATE('" . esc_sql( $args['after'] ) . "', '%Y-%m-%d %H:%i:%s') and STR_TO_DATE('" . esc_sql( $args['before'] ) . "', '%Y-%m-%d %H:%i:%s')";
+ }
+
+ if ( ! empty( $args['modified_after'] ) || ! empty( $args['modified_before'] ) ) {
+ $args['modified_after'] = empty( $args['modified_after'] ) ? '0000-00-00' : $args['modified_after'];
+ $args['modified_before'] = empty( $args['modified_before'] ) ? current_time( 'mysql', 1 ) : $args['modified_before'];
+
+ $date_modified = "AND `date_modified_gmt` BETWEEN STR_TO_DATE('" . esc_sql( $args['modified_after'] ) . "', '%Y-%m-%d %H:%i:%s') and STR_TO_DATE('" . esc_sql( $args['modified_before'] ) . "', '%Y-%m-%d %H:%i:%s')";
+ }
+
+ // Check for cache.
+ $cache_key = WC_Cache_Helper::get_cache_prefix( 'webhooks' ) . 'search_webhooks' . md5( implode( ',', $args ) );
+ $cache_value = wp_cache_get( $cache_key, 'webhook_search_results' );
+
+ if ( $cache_value ) {
+ return $cache_value;
+ }
+
+ if ( $args['paginate'] ) {
+ $query = trim(
+ "SELECT SQL_CALC_FOUND_ROWS webhook_id
+ FROM {$wpdb->prefix}wc_webhooks
+ WHERE 1=1
+ {$status}
+ {$search}
+ {$include}
+ {$exclude}
+ {$date_created}
+ {$date_modified}
+ {$order}
+ {$limit}
+ {$offset}"
+ );
+
+ $webhook_ids = wp_parse_id_list( $wpdb->get_col( $query ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
+ $total = (int) $wpdb->get_var( 'SELECT FOUND_ROWS();' );
+ $return_value = (object) array(
+ 'webhooks' => $webhook_ids,
+ 'total' => $total,
+ 'max_num_pages' => $args['limit'] > 1 ? ceil( $total / $args['limit'] ) : 1,
+ );
+ } else {
+ $query = trim(
+ "SELECT webhook_id
+ FROM {$wpdb->prefix}wc_webhooks
+ WHERE 1=1
+ {$status}
+ {$search}
+ {$include}
+ {$exclude}
+ {$date_created}
+ {$date_modified}
+ {$order}
+ {$limit}
+ {$offset}"
+ );
+
+ $webhook_ids = wp_parse_id_list( $wpdb->get_col( $query ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
+ $return_value = $webhook_ids;
+ }
+
+ wp_cache_set( $cache_key, $return_value, 'webhook_search_results' );
+
+ return $return_value;
+ }
+
+ /**
+ * Count webhooks.
+ *
+ * @since 3.6.0
+ * @param string $status Status to count.
+ * @return int
+ */
+ protected function get_webhook_count( $status = 'active' ) {
+ global $wpdb;
+ $cache_key = WC_Cache_Helper::get_cache_prefix( 'webhooks' ) . $status . '_count';
+ $count = wp_cache_get( $cache_key, 'webhooks' );
+
+ if ( false === $count ) {
+ $count = absint( $wpdb->get_var( $wpdb->prepare( "SELECT count( webhook_id ) FROM {$wpdb->prefix}wc_webhooks WHERE `status` = %s;", $status ) ) );
+
+ wp_cache_add( $cache_key, $count, 'webhooks' );
+ }
+
+ return $count;
+ }
+
+ /**
+ * Get total webhook counts by status.
+ *
+ * @return array
+ */
+ public function get_count_webhooks_by_status() {
+ $statuses = array_keys( wc_get_webhook_statuses() );
+ $counts = array();
+
+ foreach ( $statuses as $status ) {
+ $counts[ $status ] = $this->get_webhook_count( $status );
+ }
+
+ return $counts;
+ }
+
+ /**
+ * Check if a given string is in known statuses, based on return value of @see wc_get_webhook_statuses().
+ *
+ * @since 3.6.0
+ * @throws InvalidArgumentException If $status is not empty and not in the known wc_get_webhook_statuses() keys.
+ * @param string $status Status to check.
+ */
+ private function validate_status( $status ) {
+ if ( ! array_key_exists( $status, wc_get_webhook_statuses() ) ) {
+ throw new InvalidArgumentException( sprintf( 'Invalid status given: %s. Status must be one of: %s.', $status, implode( ', ', array_keys( wc_get_webhook_statuses() ) ) ) );
+ }
+ }
+
+ /**
+ * Get the transient key used to cache a set of webhook IDs, optionally filtered by status.
+ *
+ * @since 3.6.0
+ * @param string $status Optional - status of cache key.
+ * @return string
+ */
+ private function get_transient_key( $status = '' ) {
+ return empty( $status ) ? 'woocommerce_webhook_ids' : sprintf( 'woocommerce_webhook_ids_status_%s', $status );
+ }
+
+ /**
+ * Delete the transients used to cache a set of webhook IDs, optionally filtered by status.
+ *
+ * @since 3.6.0
+ * @param string $status Optional - status of cache to delete, or 'all' to delete all caches.
+ */
+ private function delete_transients( $status = '' ) {
+
+ // Always delete the non-filtered cache.
+ delete_transient( $this->get_transient_key( '' ) );
+
+ if ( ! empty( $status ) ) {
+ if ( 'all' === $status ) {
+ foreach ( wc_get_webhook_statuses() as $status_key => $status_string ) {
+ delete_transient( $this->get_transient_key( $status_key ) );
+ }
+ } else {
+ delete_transient( $this->get_transient_key( $status ) );
+ }
+ }
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-cancelled-order.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-cancelled-order.php
new file mode 100644
index 0000000..eeb4d34
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-cancelled-order.php
@@ -0,0 +1,209 @@
+id = 'cancelled_order';
+ $this->title = __( 'Cancelled order', 'woocommerce' );
+ $this->description = __( 'Cancelled order emails are sent to chosen recipient(s) when orders have been marked cancelled (if they were previously processing or on-hold).', 'woocommerce' );
+ $this->template_html = 'emails/admin-cancelled-order.php';
+ $this->template_plain = 'emails/plain/admin-cancelled-order.php';
+ $this->placeholders = array(
+ '{order_date}' => '',
+ '{order_number}' => '',
+ '{order_billing_full_name}' => '',
+ );
+
+ // Triggers for this email.
+ add_action( 'woocommerce_order_status_processing_to_cancelled_notification', array( $this, 'trigger' ), 10, 2 );
+ add_action( 'woocommerce_order_status_on-hold_to_cancelled_notification', array( $this, 'trigger' ), 10, 2 );
+
+ // Call parent constructor.
+ parent::__construct();
+
+ // Other settings.
+ $this->recipient = $this->get_option( 'recipient', get_option( 'admin_email' ) );
+ }
+
+ /**
+ * Get email subject.
+ *
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_subject() {
+ return __( '[{site_title}]: Order #{order_number} has been cancelled', 'woocommerce' );
+ }
+
+ /**
+ * Get email heading.
+ *
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_heading() {
+ return __( 'Order Cancelled: #{order_number}', 'woocommerce' );
+ }
+
+ /**
+ * Trigger the sending of this email.
+ *
+ * @param int $order_id The order ID.
+ * @param WC_Order|false $order Order object.
+ */
+ public function trigger( $order_id, $order = false ) {
+ $this->setup_locale();
+
+ if ( $order_id && ! is_a( $order, 'WC_Order' ) ) {
+ $order = wc_get_order( $order_id );
+ }
+
+ if ( is_a( $order, 'WC_Order' ) ) {
+ $this->object = $order;
+ $this->placeholders['{order_date}'] = wc_format_datetime( $this->object->get_date_created() );
+ $this->placeholders['{order_number}'] = $this->object->get_order_number();
+ $this->placeholders['{order_billing_full_name}'] = $this->object->get_formatted_billing_full_name();
+ }
+
+ if ( $this->is_enabled() && $this->get_recipient() ) {
+ $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
+ }
+
+ $this->restore_locale();
+ }
+
+ /**
+ * Get content html.
+ *
+ * @return string
+ */
+ public function get_content_html() {
+ return wc_get_template_html(
+ $this->template_html,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'sent_to_admin' => true,
+ 'plain_text' => false,
+ 'email' => $this,
+ )
+ );
+ }
+
+ /**
+ * Get content plain.
+ *
+ * @return string
+ */
+ public function get_content_plain() {
+ return wc_get_template_html(
+ $this->template_plain,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'sent_to_admin' => true,
+ 'plain_text' => true,
+ 'email' => $this,
+ )
+ );
+ }
+
+ /**
+ * Default content to show below main email content.
+ *
+ * @since 3.7.0
+ * @return string
+ */
+ public function get_default_additional_content() {
+ return __( 'Thanks for reading.', 'woocommerce' );
+ }
+
+ /**
+ * Initialise settings form fields.
+ */
+ public function init_form_fields() {
+ /* translators: %s: list of placeholders */
+ $placeholder_text = sprintf( __( 'Available placeholders: %s', 'woocommerce' ), '' . esc_html( implode( '
, ', array_keys( $this->placeholders ) ) ) . '
' );
+ $this->form_fields = array(
+ 'enabled' => array(
+ 'title' => __( 'Enable/Disable', 'woocommerce' ),
+ 'type' => 'checkbox',
+ 'label' => __( 'Enable this email notification', 'woocommerce' ),
+ 'default' => 'yes',
+ ),
+ 'recipient' => array(
+ 'title' => __( 'Recipient(s)', 'woocommerce' ),
+ 'type' => 'text',
+ /* translators: %s: admin email */
+ 'description' => sprintf( __( 'Enter recipients (comma separated) for this email. Defaults to %s.', 'woocommerce' ), '' . esc_attr( get_option( 'admin_email' ) ) . '
' ),
+ 'placeholder' => '',
+ 'default' => '',
+ 'desc_tip' => true,
+ ),
+ 'subject' => array(
+ 'title' => __( 'Subject', 'woocommerce' ),
+ 'type' => 'text',
+ 'desc_tip' => true,
+ 'description' => $placeholder_text,
+ 'placeholder' => $this->get_default_subject(),
+ 'default' => '',
+ ),
+ 'heading' => array(
+ 'title' => __( 'Email heading', 'woocommerce' ),
+ 'type' => 'text',
+ 'desc_tip' => true,
+ 'description' => $placeholder_text,
+ 'placeholder' => $this->get_default_heading(),
+ 'default' => '',
+ ),
+ 'additional_content' => array(
+ 'title' => __( 'Additional content', 'woocommerce' ),
+ 'description' => __( 'Text to appear below the main email content.', 'woocommerce' ) . ' ' . $placeholder_text,
+ 'css' => 'width:400px; height: 75px;',
+ 'placeholder' => __( 'N/A', 'woocommerce' ),
+ 'type' => 'textarea',
+ 'default' => $this->get_default_additional_content(),
+ 'desc_tip' => true,
+ ),
+ 'email_type' => array(
+ 'title' => __( 'Email type', 'woocommerce' ),
+ 'type' => 'select',
+ 'description' => __( 'Choose which format of email to send.', 'woocommerce' ),
+ 'default' => 'html',
+ 'class' => 'email_type wc-enhanced-select',
+ 'options' => $this->get_email_type_options(),
+ 'desc_tip' => true,
+ ),
+ );
+ }
+ }
+
+endif;
+
+return new WC_Email_Cancelled_Order();
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-completed-order.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-completed-order.php
new file mode 100644
index 0000000..1795867
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-completed-order.php
@@ -0,0 +1,146 @@
+id = 'customer_completed_order';
+ $this->customer_email = true;
+ $this->title = __( 'Completed order', 'woocommerce' );
+ $this->description = __( 'Order complete emails are sent to customers when their orders are marked completed and usually indicate that their orders have been shipped.', 'woocommerce' );
+ $this->template_html = 'emails/customer-completed-order.php';
+ $this->template_plain = 'emails/plain/customer-completed-order.php';
+ $this->placeholders = array(
+ '{order_date}' => '',
+ '{order_number}' => '',
+ );
+
+ // Triggers for this email.
+ add_action( 'woocommerce_order_status_completed_notification', array( $this, 'trigger' ), 10, 2 );
+
+ // Call parent constructor.
+ parent::__construct();
+ }
+
+ /**
+ * Trigger the sending of this email.
+ *
+ * @param int $order_id The order ID.
+ * @param WC_Order|false $order Order object.
+ */
+ public function trigger( $order_id, $order = false ) {
+ $this->setup_locale();
+
+ if ( $order_id && ! is_a( $order, 'WC_Order' ) ) {
+ $order = wc_get_order( $order_id );
+ }
+
+ if ( is_a( $order, 'WC_Order' ) ) {
+ $this->object = $order;
+ $this->recipient = $this->object->get_billing_email();
+ $this->placeholders['{order_date}'] = wc_format_datetime( $this->object->get_date_created() );
+ $this->placeholders['{order_number}'] = $this->object->get_order_number();
+ }
+
+ if ( $this->is_enabled() && $this->get_recipient() ) {
+ $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
+ }
+
+ $this->restore_locale();
+ }
+
+ /**
+ * Get email subject.
+ *
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_subject() {
+ return __( 'Your {site_title} order is now complete', 'woocommerce' );
+ }
+
+ /**
+ * Get email heading.
+ *
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_heading() {
+ return __( 'Thanks for shopping with us', 'woocommerce' );
+ }
+
+ /**
+ * Get content html.
+ *
+ * @return string
+ */
+ public function get_content_html() {
+ return wc_get_template_html(
+ $this->template_html,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'sent_to_admin' => false,
+ 'plain_text' => false,
+ 'email' => $this,
+ )
+ );
+ }
+
+ /**
+ * Get content plain.
+ *
+ * @return string
+ */
+ public function get_content_plain() {
+ return wc_get_template_html(
+ $this->template_plain,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'sent_to_admin' => false,
+ 'plain_text' => true,
+ 'email' => $this,
+ )
+ );
+ }
+
+ /**
+ * Default content to show below main email content.
+ *
+ * @since 3.7.0
+ * @return string
+ */
+ public function get_default_additional_content() {
+ return __( 'Thanks for shopping with us.', 'woocommerce' );
+ }
+ }
+
+endif;
+
+return new WC_Email_Customer_Completed_Order();
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-invoice.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-invoice.php
new file mode 100644
index 0000000..0a2592c
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-invoice.php
@@ -0,0 +1,246 @@
+id = 'customer_invoice';
+ $this->customer_email = true;
+ $this->title = __( 'Customer invoice / Order details', 'woocommerce' );
+ $this->description = __( 'Customer invoice emails can be sent to customers containing their order information and payment links.', 'woocommerce' );
+ $this->template_html = 'emails/customer-invoice.php';
+ $this->template_plain = 'emails/plain/customer-invoice.php';
+ $this->placeholders = array(
+ '{order_date}' => '',
+ '{order_number}' => '',
+ );
+
+ // Call parent constructor.
+ parent::__construct();
+
+ $this->manual = true;
+ }
+
+ /**
+ * Get email subject.
+ *
+ * @param bool $paid Whether the order has been paid or not.
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_subject( $paid = false ) {
+ if ( $paid ) {
+ return __( 'Invoice for order #{order_number} on {site_title}', 'woocommerce' );
+ } else {
+ return __( 'Your latest {site_title} invoice', 'woocommerce' );
+ }
+ }
+
+ /**
+ * Get email heading.
+ *
+ * @param bool $paid Whether the order has been paid or not.
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_heading( $paid = false ) {
+ if ( $paid ) {
+ return __( 'Invoice for order #{order_number}', 'woocommerce' );
+ } else {
+ return __( 'Your invoice for order #{order_number}', 'woocommerce' );
+ }
+ }
+
+ /**
+ * Get email subject.
+ *
+ * @return string
+ */
+ public function get_subject() {
+ if ( $this->object->has_status( array( 'completed', 'processing' ) ) ) {
+ $subject = $this->get_option( 'subject_paid', $this->get_default_subject( true ) );
+
+ return apply_filters( 'woocommerce_email_subject_customer_invoice_paid', $this->format_string( $subject ), $this->object, $this );
+ }
+
+ $subject = $this->get_option( 'subject', $this->get_default_subject() );
+ return apply_filters( 'woocommerce_email_subject_customer_invoice', $this->format_string( $subject ), $this->object, $this );
+ }
+
+ /**
+ * Get email heading.
+ *
+ * @return string
+ */
+ public function get_heading() {
+ if ( $this->object->has_status( wc_get_is_paid_statuses() ) ) {
+ $heading = $this->get_option( 'heading_paid', $this->get_default_heading( true ) );
+ return apply_filters( 'woocommerce_email_heading_customer_invoice_paid', $this->format_string( $heading ), $this->object, $this );
+ }
+
+ $heading = $this->get_option( 'heading', $this->get_default_heading() );
+ return apply_filters( 'woocommerce_email_heading_customer_invoice', $this->format_string( $heading ), $this->object, $this );
+ }
+
+ /**
+ * Default content to show below main email content.
+ *
+ * @since 3.7.0
+ * @return string
+ */
+ public function get_default_additional_content() {
+ return __( 'Thanks for using {site_url}!', 'woocommerce' );
+ }
+
+ /**
+ * Trigger the sending of this email.
+ *
+ * @param int $order_id The order ID.
+ * @param WC_Order $order Order object.
+ */
+ public function trigger( $order_id, $order = false ) {
+ $this->setup_locale();
+
+ if ( $order_id && ! is_a( $order, 'WC_Order' ) ) {
+ $order = wc_get_order( $order_id );
+ }
+
+ if ( is_a( $order, 'WC_Order' ) ) {
+ $this->object = $order;
+ $this->recipient = $this->object->get_billing_email();
+ $this->placeholders['{order_date}'] = wc_format_datetime( $this->object->get_date_created() );
+ $this->placeholders['{order_number}'] = $this->object->get_order_number();
+ }
+
+ if ( $this->get_recipient() ) {
+ $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
+ }
+
+ $this->restore_locale();
+ }
+
+ /**
+ * Get content html.
+ *
+ * @return string
+ */
+ public function get_content_html() {
+ return wc_get_template_html(
+ $this->template_html,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'sent_to_admin' => false,
+ 'plain_text' => false,
+ 'email' => $this,
+ )
+ );
+ }
+
+ /**
+ * Get content plain.
+ *
+ * @return string
+ */
+ public function get_content_plain() {
+ return wc_get_template_html(
+ $this->template_plain,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'sent_to_admin' => false,
+ 'plain_text' => true,
+ 'email' => $this,
+ )
+ );
+ }
+
+ /**
+ * Initialise settings form fields.
+ */
+ public function init_form_fields() {
+ /* translators: %s: list of placeholders */
+ $placeholder_text = sprintf( __( 'Available placeholders: %s', 'woocommerce' ), '' . esc_html( implode( '
, ', array_keys( $this->placeholders ) ) ) . '
' );
+ $this->form_fields = array(
+ 'subject' => array(
+ 'title' => __( 'Subject', 'woocommerce' ),
+ 'type' => 'text',
+ 'desc_tip' => true,
+ 'description' => $placeholder_text,
+ 'placeholder' => $this->get_default_subject(),
+ 'default' => '',
+ ),
+ 'heading' => array(
+ 'title' => __( 'Email heading', 'woocommerce' ),
+ 'type' => 'text',
+ 'desc_tip' => true,
+ 'description' => $placeholder_text,
+ 'placeholder' => $this->get_default_heading(),
+ 'default' => '',
+ ),
+ 'subject_paid' => array(
+ 'title' => __( 'Subject (paid)', 'woocommerce' ),
+ 'type' => 'text',
+ 'desc_tip' => true,
+ 'description' => $placeholder_text,
+ 'placeholder' => $this->get_default_subject( true ),
+ 'default' => '',
+ ),
+ 'heading_paid' => array(
+ 'title' => __( 'Email heading (paid)', 'woocommerce' ),
+ 'type' => 'text',
+ 'desc_tip' => true,
+ 'description' => $placeholder_text,
+ 'placeholder' => $this->get_default_heading( true ),
+ 'default' => '',
+ ),
+ 'additional_content' => array(
+ 'title' => __( 'Additional content', 'woocommerce' ),
+ 'description' => __( 'Text to appear below the main email content.', 'woocommerce' ) . ' ' . $placeholder_text,
+ 'css' => 'width:400px; height: 75px;',
+ 'placeholder' => __( 'N/A', 'woocommerce' ),
+ 'type' => 'textarea',
+ 'default' => $this->get_default_additional_content(),
+ 'desc_tip' => true,
+ ),
+ 'email_type' => array(
+ 'title' => __( 'Email type', 'woocommerce' ),
+ 'type' => 'select',
+ 'description' => __( 'Choose which format of email to send.', 'woocommerce' ),
+ 'default' => 'html',
+ 'class' => 'email_type wc-enhanced-select',
+ 'options' => $this->get_email_type_options(),
+ 'desc_tip' => true,
+ ),
+ );
+ }
+ }
+
+endif;
+
+return new WC_Email_Customer_Invoice();
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-new-account.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-new-account.php
new file mode 100644
index 0000000..3cd0a82
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-new-account.php
@@ -0,0 +1,173 @@
+id = 'customer_new_account';
+ $this->customer_email = true;
+ $this->title = __( 'New account', 'woocommerce' );
+ $this->description = __( 'Customer "new account" emails are sent to the customer when a customer signs up via checkout or account pages.', 'woocommerce' );
+ $this->template_html = 'emails/customer-new-account.php';
+ $this->template_plain = 'emails/plain/customer-new-account.php';
+
+ // Call parent constructor.
+ parent::__construct();
+ }
+
+ /**
+ * Get email subject.
+ *
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_subject() {
+ return __( 'Your {site_title} account has been created!', 'woocommerce' );
+ }
+
+ /**
+ * Get email heading.
+ *
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_heading() {
+ return __( 'Welcome to {site_title}', 'woocommerce' );
+ }
+
+ /**
+ * Trigger.
+ *
+ * @param int $user_id User ID.
+ * @param string $user_pass User password.
+ * @param bool $password_generated Whether the password was generated automatically or not.
+ */
+ public function trigger( $user_id, $user_pass = '', $password_generated = false ) {
+ $this->setup_locale();
+
+ if ( $user_id ) {
+ $this->object = new WP_User( $user_id );
+
+ $this->user_pass = $user_pass;
+ $this->user_login = stripslashes( $this->object->user_login );
+ $this->user_email = stripslashes( $this->object->user_email );
+ $this->recipient = $this->user_email;
+ $this->password_generated = $password_generated;
+ }
+
+ if ( $this->is_enabled() && $this->get_recipient() ) {
+ $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
+ }
+
+ $this->restore_locale();
+ }
+
+ /**
+ * Get content html.
+ *
+ * @return string
+ */
+ public function get_content_html() {
+ return wc_get_template_html(
+ $this->template_html,
+ array(
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'user_login' => $this->user_login,
+ 'user_pass' => $this->user_pass,
+ 'blogname' => $this->get_blogname(),
+ 'password_generated' => $this->password_generated,
+ 'sent_to_admin' => false,
+ 'plain_text' => false,
+ 'email' => $this,
+ )
+ );
+ }
+
+ /**
+ * Get content plain.
+ *
+ * @return string
+ */
+ public function get_content_plain() {
+ return wc_get_template_html(
+ $this->template_plain,
+ array(
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'user_login' => $this->user_login,
+ 'user_pass' => $this->user_pass,
+ 'blogname' => $this->get_blogname(),
+ 'password_generated' => $this->password_generated,
+ 'sent_to_admin' => false,
+ 'plain_text' => true,
+ 'email' => $this,
+ )
+ );
+ }
+
+ /**
+ * Default content to show below main email content.
+ *
+ * @since 3.7.0
+ * @return string
+ */
+ public function get_default_additional_content() {
+ return __( 'We look forward to seeing you soon.', 'woocommerce' );
+ }
+ }
+
+endif;
+
+return new WC_Email_Customer_New_Account();
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-note.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-note.php
new file mode 100644
index 0000000..cf1b265
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-note.php
@@ -0,0 +1,166 @@
+id = 'customer_note';
+ $this->customer_email = true;
+ $this->title = __( 'Customer note', 'woocommerce' );
+ $this->description = __( 'Customer note emails are sent when you add a note to an order.', 'woocommerce' );
+ $this->template_html = 'emails/customer-note.php';
+ $this->template_plain = 'emails/plain/customer-note.php';
+ $this->placeholders = array(
+ '{order_date}' => '',
+ '{order_number}' => '',
+ );
+
+ // Triggers.
+ add_action( 'woocommerce_new_customer_note_notification', array( $this, 'trigger' ) );
+
+ // Call parent constructor.
+ parent::__construct();
+ }
+
+ /**
+ * Get email subject.
+ *
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_subject() {
+ return __( 'Note added to your {site_title} order from {order_date}', 'woocommerce' );
+ }
+
+ /**
+ * Get email heading.
+ *
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_heading() {
+ return __( 'A note has been added to your order', 'woocommerce' );
+ }
+
+ /**
+ * Trigger.
+ *
+ * @param array $args Email arguments.
+ */
+ public function trigger( $args ) {
+ $this->setup_locale();
+
+ if ( ! empty( $args ) ) {
+ $defaults = array(
+ 'order_id' => '',
+ 'customer_note' => '',
+ );
+
+ $args = wp_parse_args( $args, $defaults );
+
+ $order_id = $args['order_id'];
+ $customer_note = $args['customer_note'];
+
+ if ( $order_id ) {
+ $this->object = wc_get_order( $order_id );
+
+ if ( $this->object ) {
+ $this->recipient = $this->object->get_billing_email();
+ $this->customer_note = $customer_note;
+ $this->placeholders['{order_date}'] = wc_format_datetime( $this->object->get_date_created() );
+ $this->placeholders['{order_number}'] = $this->object->get_order_number();
+ }
+ }
+ }
+
+ if ( $this->is_enabled() && $this->get_recipient() ) {
+ $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
+ }
+
+ $this->restore_locale();
+ }
+
+ /**
+ * Get content html.
+ *
+ * @return string
+ */
+ public function get_content_html() {
+ return wc_get_template_html(
+ $this->template_html,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'customer_note' => $this->customer_note,
+ 'sent_to_admin' => false,
+ 'plain_text' => false,
+ 'email' => $this,
+ )
+ );
+ }
+
+ /**
+ * Get content plain.
+ *
+ * @return string
+ */
+ public function get_content_plain() {
+ return wc_get_template_html(
+ $this->template_plain,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'customer_note' => $this->customer_note,
+ 'sent_to_admin' => false,
+ 'plain_text' => true,
+ 'email' => $this,
+ )
+ );
+ }
+
+ /**
+ * Default content to show below main email content.
+ *
+ * @since 3.7.0
+ * @return string
+ */
+ public function get_default_additional_content() {
+ return __( 'Thanks for reading.', 'woocommerce' );
+ }
+ }
+
+endif;
+
+return new WC_Email_Customer_Note();
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-on-hold-order.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-on-hold-order.php
new file mode 100644
index 0000000..080abb9
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-on-hold-order.php
@@ -0,0 +1,148 @@
+id = 'customer_on_hold_order';
+ $this->customer_email = true;
+ $this->title = __( 'Order on-hold', 'woocommerce' );
+ $this->description = __( 'This is an order notification sent to customers containing order details after an order is placed on-hold.', 'woocommerce' );
+ $this->template_html = 'emails/customer-on-hold-order.php';
+ $this->template_plain = 'emails/plain/customer-on-hold-order.php';
+ $this->placeholders = array(
+ '{order_date}' => '',
+ '{order_number}' => '',
+ );
+
+ // Triggers for this email.
+ add_action( 'woocommerce_order_status_pending_to_on-hold_notification', array( $this, 'trigger' ), 10, 2 );
+ add_action( 'woocommerce_order_status_failed_to_on-hold_notification', array( $this, 'trigger' ), 10, 2 );
+ add_action( 'woocommerce_order_status_cancelled_to_on-hold_notification', array( $this, 'trigger' ), 10, 2 );
+
+ // Call parent constructor.
+ parent::__construct();
+ }
+
+ /**
+ * Get email subject.
+ *
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_subject() {
+ return __( 'Your {site_title} order has been received!', 'woocommerce' );
+ }
+
+ /**
+ * Get email heading.
+ *
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_heading() {
+ return __( 'Thank you for your order', 'woocommerce' );
+ }
+
+ /**
+ * Trigger the sending of this email.
+ *
+ * @param int $order_id The order ID.
+ * @param WC_Order|false $order Order object.
+ */
+ public function trigger( $order_id, $order = false ) {
+ $this->setup_locale();
+
+ if ( $order_id && ! is_a( $order, 'WC_Order' ) ) {
+ $order = wc_get_order( $order_id );
+ }
+
+ if ( is_a( $order, 'WC_Order' ) ) {
+ $this->object = $order;
+ $this->recipient = $this->object->get_billing_email();
+ $this->placeholders['{order_date}'] = wc_format_datetime( $this->object->get_date_created() );
+ $this->placeholders['{order_number}'] = $this->object->get_order_number();
+ }
+
+ if ( $this->is_enabled() && $this->get_recipient() ) {
+ $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
+ }
+
+ $this->restore_locale();
+ }
+
+ /**
+ * Get content html.
+ *
+ * @return string
+ */
+ public function get_content_html() {
+ return wc_get_template_html(
+ $this->template_html,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'sent_to_admin' => false,
+ 'plain_text' => false,
+ 'email' => $this,
+ )
+ );
+ }
+
+ /**
+ * Get content plain.
+ *
+ * @return string
+ */
+ public function get_content_plain() {
+ return wc_get_template_html(
+ $this->template_plain,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'sent_to_admin' => false,
+ 'plain_text' => true,
+ 'email' => $this,
+ )
+ );
+ }
+
+ /**
+ * Default content to show below main email content.
+ *
+ * @since 3.7.0
+ * @return string
+ */
+ public function get_default_additional_content() {
+ return __( 'We look forward to fulfilling your order soon.', 'woocommerce' );
+ }
+ }
+
+endif;
+
+return new WC_Email_Customer_On_Hold_Order();
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-processing-order.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-processing-order.php
new file mode 100644
index 0000000..18b8c95
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-processing-order.php
@@ -0,0 +1,150 @@
+id = 'customer_processing_order';
+ $this->customer_email = true;
+
+ $this->title = __( 'Processing order', 'woocommerce' );
+ $this->description = __( 'This is an order notification sent to customers containing order details after payment.', 'woocommerce' );
+ $this->template_html = 'emails/customer-processing-order.php';
+ $this->template_plain = 'emails/plain/customer-processing-order.php';
+ $this->placeholders = array(
+ '{order_date}' => '',
+ '{order_number}' => '',
+ );
+
+ // Triggers for this email.
+ add_action( 'woocommerce_order_status_cancelled_to_processing_notification', array( $this, 'trigger' ), 10, 2 );
+ add_action( 'woocommerce_order_status_failed_to_processing_notification', array( $this, 'trigger' ), 10, 2 );
+ add_action( 'woocommerce_order_status_on-hold_to_processing_notification', array( $this, 'trigger' ), 10, 2 );
+ add_action( 'woocommerce_order_status_pending_to_processing_notification', array( $this, 'trigger' ), 10, 2 );
+
+ // Call parent constructor.
+ parent::__construct();
+ }
+
+ /**
+ * Get email subject.
+ *
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_subject() {
+ return __( 'Your {site_title} order has been received!', 'woocommerce' );
+ }
+
+ /**
+ * Get email heading.
+ *
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_heading() {
+ return __( 'Thank you for your order', 'woocommerce' );
+ }
+
+ /**
+ * Trigger the sending of this email.
+ *
+ * @param int $order_id The order ID.
+ * @param WC_Order|false $order Order object.
+ */
+ public function trigger( $order_id, $order = false ) {
+ $this->setup_locale();
+
+ if ( $order_id && ! is_a( $order, 'WC_Order' ) ) {
+ $order = wc_get_order( $order_id );
+ }
+
+ if ( is_a( $order, 'WC_Order' ) ) {
+ $this->object = $order;
+ $this->recipient = $this->object->get_billing_email();
+ $this->placeholders['{order_date}'] = wc_format_datetime( $this->object->get_date_created() );
+ $this->placeholders['{order_number}'] = $this->object->get_order_number();
+ }
+
+ if ( $this->is_enabled() && $this->get_recipient() ) {
+ $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
+ }
+
+ $this->restore_locale();
+ }
+
+ /**
+ * Get content html.
+ *
+ * @return string
+ */
+ public function get_content_html() {
+ return wc_get_template_html(
+ $this->template_html,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'sent_to_admin' => false,
+ 'plain_text' => false,
+ 'email' => $this,
+ )
+ );
+ }
+
+ /**
+ * Get content plain.
+ *
+ * @return string
+ */
+ public function get_content_plain() {
+ return wc_get_template_html(
+ $this->template_plain,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'sent_to_admin' => false,
+ 'plain_text' => true,
+ 'email' => $this,
+ )
+ );
+ }
+
+ /**
+ * Default content to show below main email content.
+ *
+ * @since 3.7.0
+ * @return string
+ */
+ public function get_default_additional_content() {
+ return __( 'Thanks for using {site_url}!', 'woocommerce' );
+ }
+ }
+
+endif;
+
+return new WC_Email_Customer_Processing_Order();
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-refunded-order.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-refunded-order.php
new file mode 100644
index 0000000..1536ba3
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-refunded-order.php
@@ -0,0 +1,302 @@
+customer_email = true;
+ $this->id = 'customer_refunded_order';
+ $this->title = __( 'Refunded order', 'woocommerce' );
+ $this->description = __( 'Order refunded emails are sent to customers when their orders are refunded.', 'woocommerce' );
+ $this->template_html = 'emails/customer-refunded-order.php';
+ $this->template_plain = 'emails/plain/customer-refunded-order.php';
+ $this->placeholders = array(
+ '{order_date}' => '',
+ '{order_number}' => '',
+ );
+
+ // Triggers for this email.
+ add_action( 'woocommerce_order_fully_refunded_notification', array( $this, 'trigger_full' ), 10, 2 );
+ add_action( 'woocommerce_order_partially_refunded_notification', array( $this, 'trigger_partial' ), 10, 2 );
+
+ // Call parent constructor.
+ parent::__construct();
+ }
+
+ /**
+ * Get email subject.
+ *
+ * @param bool $partial Whether it is a partial refund or a full refund.
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_subject( $partial = false ) {
+ if ( $partial ) {
+ return __( 'Your {site_title} order #{order_number} has been partially refunded', 'woocommerce' );
+ } else {
+ return __( 'Your {site_title} order #{order_number} has been refunded', 'woocommerce' );
+ }
+ }
+
+ /**
+ * Get email heading.
+ *
+ * @param bool $partial Whether it is a partial refund or a full refund.
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_heading( $partial = false ) {
+ if ( $partial ) {
+ return __( 'Partial Refund: Order {order_number}', 'woocommerce' );
+ } else {
+ return __( 'Order Refunded: {order_number}', 'woocommerce' );
+ }
+ }
+
+ /**
+ * Get email subject.
+ *
+ * @return string
+ */
+ public function get_subject() {
+ if ( $this->partial_refund ) {
+ $subject = $this->get_option( 'subject_partial', $this->get_default_subject( true ) );
+ } else {
+ $subject = $this->get_option( 'subject_full', $this->get_default_subject() );
+ }
+ return apply_filters( 'woocommerce_email_subject_customer_refunded_order', $this->format_string( $subject ), $this->object, $this );
+ }
+
+ /**
+ * Get email heading.
+ *
+ * @return string
+ */
+ public function get_heading() {
+ if ( $this->partial_refund ) {
+ $heading = $this->get_option( 'heading_partial', $this->get_default_heading( true ) );
+ } else {
+ $heading = $this->get_option( 'heading_full', $this->get_default_heading() );
+ }
+ return apply_filters( 'woocommerce_email_heading_customer_refunded_order', $this->format_string( $heading ), $this->object, $this );
+ }
+
+ /**
+ * Set email strings.
+ *
+ * @param bool $partial_refund Whether it is a partial refund or a full refund.
+ * @deprecated 3.1.0 Unused.
+ */
+ public function set_email_strings( $partial_refund = false ) {}
+
+ /**
+ * Full refund notification.
+ *
+ * @param int $order_id Order ID.
+ * @param int $refund_id Refund ID.
+ */
+ public function trigger_full( $order_id, $refund_id = null ) {
+ $this->trigger( $order_id, false, $refund_id );
+ }
+
+ /**
+ * Partial refund notification.
+ *
+ * @param int $order_id Order ID.
+ * @param int $refund_id Refund ID.
+ */
+ public function trigger_partial( $order_id, $refund_id = null ) {
+ $this->trigger( $order_id, true, $refund_id );
+ }
+
+ /**
+ * Trigger.
+ *
+ * @param int $order_id Order ID.
+ * @param bool $partial_refund Whether it is a partial refund or a full refund.
+ * @param int $refund_id Refund ID.
+ */
+ public function trigger( $order_id, $partial_refund = false, $refund_id = null ) {
+ $this->setup_locale();
+ $this->partial_refund = $partial_refund;
+ $this->id = $this->partial_refund ? 'customer_partially_refunded_order' : 'customer_refunded_order';
+
+ if ( $order_id ) {
+ $this->object = wc_get_order( $order_id );
+ $this->recipient = $this->object->get_billing_email();
+ $this->placeholders['{order_date}'] = wc_format_datetime( $this->object->get_date_created() );
+ $this->placeholders['{order_number}'] = $this->object->get_order_number();
+ }
+
+ if ( ! empty( $refund_id ) ) {
+ $this->refund = wc_get_order( $refund_id );
+ } else {
+ $this->refund = false;
+ }
+
+ if ( $this->is_enabled() && $this->get_recipient() ) {
+ $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
+ }
+
+ $this->restore_locale();
+ }
+
+ /**
+ * Get content html.
+ *
+ * @return string
+ */
+ public function get_content_html() {
+ return wc_get_template_html(
+ $this->template_html,
+ array(
+ 'order' => $this->object,
+ 'refund' => $this->refund,
+ 'partial_refund' => $this->partial_refund,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'sent_to_admin' => false,
+ 'plain_text' => false,
+ 'email' => $this,
+ )
+ );
+ }
+
+ /**
+ * Get content plain.
+ *
+ * @return string
+ */
+ public function get_content_plain() {
+ return wc_get_template_html(
+ $this->template_plain,
+ array(
+ 'order' => $this->object,
+ 'refund' => $this->refund,
+ 'partial_refund' => $this->partial_refund,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'sent_to_admin' => false,
+ 'plain_text' => true,
+ 'email' => $this,
+ )
+ );
+ }
+
+ /**
+ * Default content to show below main email content.
+ *
+ * @since 3.7.0
+ * @return string
+ */
+ public function get_default_additional_content() {
+ return __( 'We hope to see you again soon.', 'woocommerce' );
+ }
+
+ /**
+ * Initialise settings form fields.
+ */
+ public function init_form_fields() {
+ /* translators: %s: list of placeholders */
+ $placeholder_text = sprintf( __( 'Available placeholders: %s', 'woocommerce' ), '' . esc_html( implode( '
, ', array_keys( $this->placeholders ) ) ) . '
' );
+ $this->form_fields = array(
+ 'enabled' => array(
+ 'title' => __( 'Enable/Disable', 'woocommerce' ),
+ 'type' => 'checkbox',
+ 'label' => __( 'Enable this email notification', 'woocommerce' ),
+ 'default' => 'yes',
+ ),
+ 'subject_full' => array(
+ 'title' => __( 'Full refund subject', 'woocommerce' ),
+ 'type' => 'text',
+ 'desc_tip' => true,
+ 'description' => $placeholder_text,
+ 'placeholder' => $this->get_default_subject(),
+ 'default' => '',
+ ),
+ 'subject_partial' => array(
+ 'title' => __( 'Partial refund subject', 'woocommerce' ),
+ 'type' => 'text',
+ 'desc_tip' => true,
+ 'description' => $placeholder_text,
+ 'placeholder' => $this->get_default_subject( true ),
+ 'default' => '',
+ ),
+ 'heading_full' => array(
+ 'title' => __( 'Full refund email heading', 'woocommerce' ),
+ 'type' => 'text',
+ 'desc_tip' => true,
+ 'description' => $placeholder_text,
+ 'placeholder' => $this->get_default_heading(),
+ 'default' => '',
+ ),
+ 'heading_partial' => array(
+ 'title' => __( 'Partial refund email heading', 'woocommerce' ),
+ 'type' => 'text',
+ 'desc_tip' => true,
+ 'description' => $placeholder_text,
+ 'placeholder' => $this->get_default_heading( true ),
+ 'default' => '',
+ ),
+ 'additional_content' => array(
+ 'title' => __( 'Additional content', 'woocommerce' ),
+ 'description' => __( 'Text to appear below the main email content.', 'woocommerce' ) . ' ' . $placeholder_text,
+ 'css' => 'width:400px; height: 75px;',
+ 'placeholder' => __( 'N/A', 'woocommerce' ),
+ 'type' => 'textarea',
+ 'default' => $this->get_default_additional_content(),
+ 'desc_tip' => true,
+ ),
+ 'email_type' => array(
+ 'title' => __( 'Email type', 'woocommerce' ),
+ 'type' => 'select',
+ 'description' => __( 'Choose which format of email to send.', 'woocommerce' ),
+ 'default' => 'html',
+ 'class' => 'email_type wc-enhanced-select',
+ 'options' => $this->get_email_type_options(),
+ 'desc_tip' => true,
+ ),
+ );
+ }
+ }
+
+endif;
+
+return new WC_Email_Customer_Refunded_Order();
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-reset-password.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-reset-password.php
new file mode 100644
index 0000000..7603097
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-customer-reset-password.php
@@ -0,0 +1,177 @@
+id = 'customer_reset_password';
+ $this->customer_email = true;
+
+ $this->title = __( 'Reset password', 'woocommerce' );
+ $this->description = __( 'Customer "reset password" emails are sent when customers reset their passwords.', 'woocommerce' );
+
+ $this->template_html = 'emails/customer-reset-password.php';
+ $this->template_plain = 'emails/plain/customer-reset-password.php';
+
+ // Trigger.
+ add_action( 'woocommerce_reset_password_notification', array( $this, 'trigger' ), 10, 2 );
+
+ // Call parent constructor.
+ parent::__construct();
+ }
+
+ /**
+ * Get email subject.
+ *
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_subject() {
+ return __( 'Password Reset Request for {site_title}', 'woocommerce' );
+ }
+
+ /**
+ * Get email heading.
+ *
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_heading() {
+ return __( 'Password Reset Request', 'woocommerce' );
+ }
+
+ /**
+ * Trigger.
+ *
+ * @param string $user_login User login.
+ * @param string $reset_key Password reset key.
+ */
+ public function trigger( $user_login = '', $reset_key = '' ) {
+ $this->setup_locale();
+
+ if ( $user_login && $reset_key ) {
+ $this->object = get_user_by( 'login', $user_login );
+ $this->user_id = $this->object->ID;
+ $this->user_login = $user_login;
+ $this->reset_key = $reset_key;
+ $this->user_email = stripslashes( $this->object->user_email );
+ $this->recipient = $this->user_email;
+ }
+
+ if ( $this->is_enabled() && $this->get_recipient() ) {
+ $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
+ }
+
+ $this->restore_locale();
+ }
+
+ /**
+ * Get content html.
+ *
+ * @return string
+ */
+ public function get_content_html() {
+ return wc_get_template_html(
+ $this->template_html,
+ array(
+ 'email_heading' => $this->get_heading(),
+ 'user_id' => $this->user_id,
+ 'user_login' => $this->user_login,
+ 'reset_key' => $this->reset_key,
+ 'blogname' => $this->get_blogname(),
+ 'additional_content' => $this->get_additional_content(),
+ 'sent_to_admin' => false,
+ 'plain_text' => false,
+ 'email' => $this,
+ )
+ );
+ }
+
+ /**
+ * Get content plain.
+ *
+ * @return string
+ */
+ public function get_content_plain() {
+ return wc_get_template_html(
+ $this->template_plain,
+ array(
+ 'email_heading' => $this->get_heading(),
+ 'user_id' => $this->user_id,
+ 'user_login' => $this->user_login,
+ 'reset_key' => $this->reset_key,
+ 'blogname' => $this->get_blogname(),
+ 'additional_content' => $this->get_additional_content(),
+ 'sent_to_admin' => false,
+ 'plain_text' => true,
+ 'email' => $this,
+ )
+ );
+ }
+
+ /**
+ * Default content to show below main email content.
+ *
+ * @since 3.7.0
+ * @return string
+ */
+ public function get_default_additional_content() {
+ return __( 'Thanks for reading.', 'woocommerce' );
+ }
+ }
+
+endif;
+
+return new WC_Email_Customer_Reset_Password();
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-failed-order.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-failed-order.php
new file mode 100644
index 0000000..0766d9a
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-failed-order.php
@@ -0,0 +1,207 @@
+id = 'failed_order';
+ $this->title = __( 'Failed order', 'woocommerce' );
+ $this->description = __( 'Failed order emails are sent to chosen recipient(s) when orders have been marked failed (if they were previously pending or on-hold).', 'woocommerce' );
+ $this->template_html = 'emails/admin-failed-order.php';
+ $this->template_plain = 'emails/plain/admin-failed-order.php';
+ $this->placeholders = array(
+ '{order_date}' => '',
+ '{order_number}' => '',
+ );
+
+ // Triggers for this email.
+ add_action( 'woocommerce_order_status_pending_to_failed_notification', array( $this, 'trigger' ), 10, 2 );
+ add_action( 'woocommerce_order_status_on-hold_to_failed_notification', array( $this, 'trigger' ), 10, 2 );
+
+ // Call parent constructor.
+ parent::__construct();
+
+ // Other settings.
+ $this->recipient = $this->get_option( 'recipient', get_option( 'admin_email' ) );
+ }
+
+ /**
+ * Get email subject.
+ *
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_subject() {
+ return __( '[{site_title}]: Order #{order_number} has failed', 'woocommerce' );
+ }
+
+ /**
+ * Get email heading.
+ *
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_heading() {
+ return __( 'Order Failed: #{order_number}', 'woocommerce' );
+ }
+
+ /**
+ * Trigger the sending of this email.
+ *
+ * @param int $order_id The order ID.
+ * @param WC_Order|false $order Order object.
+ */
+ public function trigger( $order_id, $order = false ) {
+ $this->setup_locale();
+
+ if ( $order_id && ! is_a( $order, 'WC_Order' ) ) {
+ $order = wc_get_order( $order_id );
+ }
+
+ if ( is_a( $order, 'WC_Order' ) ) {
+ $this->object = $order;
+ $this->placeholders['{order_date}'] = wc_format_datetime( $this->object->get_date_created() );
+ $this->placeholders['{order_number}'] = $this->object->get_order_number();
+ }
+
+ if ( $this->is_enabled() && $this->get_recipient() ) {
+ $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
+ }
+
+ $this->restore_locale();
+ }
+
+ /**
+ * Get content html.
+ *
+ * @return string
+ */
+ public function get_content_html() {
+ return wc_get_template_html(
+ $this->template_html,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'sent_to_admin' => true,
+ 'plain_text' => false,
+ 'email' => $this,
+ )
+ );
+ }
+
+ /**
+ * Get content plain.
+ *
+ * @return string
+ */
+ public function get_content_plain() {
+ return wc_get_template_html(
+ $this->template_plain,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'sent_to_admin' => true,
+ 'plain_text' => true,
+ 'email' => $this,
+ )
+ );
+ }
+
+ /**
+ * Default content to show below main email content.
+ *
+ * @since 3.7.0
+ * @return string
+ */
+ public function get_default_additional_content() {
+ return __( 'Hopefully they’ll be back. Read more about troubleshooting failed payments.', 'woocommerce' );
+ }
+
+ /**
+ * Initialise settings form fields.
+ */
+ public function init_form_fields() {
+ /* translators: %s: list of placeholders */
+ $placeholder_text = sprintf( __( 'Available placeholders: %s', 'woocommerce' ), '' . esc_html( implode( '
, ', array_keys( $this->placeholders ) ) ) . '
' );
+ $this->form_fields = array(
+ 'enabled' => array(
+ 'title' => __( 'Enable/Disable', 'woocommerce' ),
+ 'type' => 'checkbox',
+ 'label' => __( 'Enable this email notification', 'woocommerce' ),
+ 'default' => 'yes',
+ ),
+ 'recipient' => array(
+ 'title' => __( 'Recipient(s)', 'woocommerce' ),
+ 'type' => 'text',
+ /* translators: %s: WP admin email */
+ 'description' => sprintf( __( 'Enter recipients (comma separated) for this email. Defaults to %s.', 'woocommerce' ), '' . esc_attr( get_option( 'admin_email' ) ) . '
' ),
+ 'placeholder' => '',
+ 'default' => '',
+ 'desc_tip' => true,
+ ),
+ 'subject' => array(
+ 'title' => __( 'Subject', 'woocommerce' ),
+ 'type' => 'text',
+ 'desc_tip' => true,
+ 'description' => $placeholder_text,
+ 'placeholder' => $this->get_default_subject(),
+ 'default' => '',
+ ),
+ 'heading' => array(
+ 'title' => __( 'Email heading', 'woocommerce' ),
+ 'type' => 'text',
+ 'desc_tip' => true,
+ 'description' => $placeholder_text,
+ 'placeholder' => $this->get_default_heading(),
+ 'default' => '',
+ ),
+ 'additional_content' => array(
+ 'title' => __( 'Additional content', 'woocommerce' ),
+ 'description' => __( 'Text to appear below the main email content.', 'woocommerce' ) . ' ' . $placeholder_text,
+ 'css' => 'width:400px; height: 75px;',
+ 'placeholder' => __( 'N/A', 'woocommerce' ),
+ 'type' => 'textarea',
+ 'default' => $this->get_default_additional_content(),
+ 'desc_tip' => true,
+ ),
+ 'email_type' => array(
+ 'title' => __( 'Email type', 'woocommerce' ),
+ 'type' => 'select',
+ 'description' => __( 'Choose which format of email to send.', 'woocommerce' ),
+ 'default' => 'html',
+ 'class' => 'email_type wc-enhanced-select',
+ 'options' => $this->get_email_type_options(),
+ 'desc_tip' => true,
+ ),
+ );
+ }
+ }
+
+endif;
+
+return new WC_Email_Failed_Order();
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-new-order.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-new-order.php
new file mode 100644
index 0000000..0c063d6
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email-new-order.php
@@ -0,0 +1,214 @@
+id = 'new_order';
+ $this->title = __( 'New order', 'woocommerce' );
+ $this->description = __( 'New order emails are sent to chosen recipient(s) when a new order is received.', 'woocommerce' );
+ $this->template_html = 'emails/admin-new-order.php';
+ $this->template_plain = 'emails/plain/admin-new-order.php';
+ $this->placeholders = array(
+ '{order_date}' => '',
+ '{order_number}' => '',
+ );
+
+ // Triggers for this email.
+ add_action( 'woocommerce_order_status_pending_to_processing_notification', array( $this, 'trigger' ), 10, 2 );
+ add_action( 'woocommerce_order_status_pending_to_completed_notification', array( $this, 'trigger' ), 10, 2 );
+ add_action( 'woocommerce_order_status_pending_to_on-hold_notification', array( $this, 'trigger' ), 10, 2 );
+ add_action( 'woocommerce_order_status_failed_to_processing_notification', array( $this, 'trigger' ), 10, 2 );
+ add_action( 'woocommerce_order_status_failed_to_completed_notification', array( $this, 'trigger' ), 10, 2 );
+ add_action( 'woocommerce_order_status_failed_to_on-hold_notification', array( $this, 'trigger' ), 10, 2 );
+ add_action( 'woocommerce_order_status_cancelled_to_processing_notification', array( $this, 'trigger' ), 10, 2 );
+ add_action( 'woocommerce_order_status_cancelled_to_completed_notification', array( $this, 'trigger' ), 10, 2 );
+ add_action( 'woocommerce_order_status_cancelled_to_on-hold_notification', array( $this, 'trigger' ), 10, 2 );
+
+ // Call parent constructor.
+ parent::__construct();
+
+ // Other settings.
+ $this->recipient = $this->get_option( 'recipient', get_option( 'admin_email' ) );
+ }
+
+ /**
+ * Get email subject.
+ *
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_subject() {
+ return __( '[{site_title}]: New order #{order_number}', 'woocommerce' );
+ }
+
+ /**
+ * Get email heading.
+ *
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_heading() {
+ return __( 'New Order: #{order_number}', 'woocommerce' );
+ }
+
+ /**
+ * Trigger the sending of this email.
+ *
+ * @param int $order_id The order ID.
+ * @param WC_Order|false $order Order object.
+ */
+ public function trigger( $order_id, $order = false ) {
+ $this->setup_locale();
+
+ if ( $order_id && ! is_a( $order, 'WC_Order' ) ) {
+ $order = wc_get_order( $order_id );
+ }
+
+ if ( is_a( $order, 'WC_Order' ) ) {
+ $this->object = $order;
+ $this->placeholders['{order_date}'] = wc_format_datetime( $this->object->get_date_created() );
+ $this->placeholders['{order_number}'] = $this->object->get_order_number();
+ }
+
+ if ( $this->is_enabled() && $this->get_recipient() ) {
+ $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
+ }
+
+ $this->restore_locale();
+ }
+
+ /**
+ * Get content html.
+ *
+ * @return string
+ */
+ public function get_content_html() {
+ return wc_get_template_html(
+ $this->template_html,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'sent_to_admin' => true,
+ 'plain_text' => false,
+ 'email' => $this,
+ )
+ );
+ }
+
+ /**
+ * Get content plain.
+ *
+ * @return string
+ */
+ public function get_content_plain() {
+ return wc_get_template_html(
+ $this->template_plain,
+ array(
+ 'order' => $this->object,
+ 'email_heading' => $this->get_heading(),
+ 'additional_content' => $this->get_additional_content(),
+ 'sent_to_admin' => true,
+ 'plain_text' => true,
+ 'email' => $this,
+ )
+ );
+ }
+
+ /**
+ * Default content to show below main email content.
+ *
+ * @since 3.7.0
+ * @return string
+ */
+ public function get_default_additional_content() {
+ return __( 'Congratulations on the sale.', 'woocommerce' );
+ }
+
+ /**
+ * Initialise settings form fields.
+ */
+ public function init_form_fields() {
+ /* translators: %s: list of placeholders */
+ $placeholder_text = sprintf( __( 'Available placeholders: %s', 'woocommerce' ), '' . implode( '
, ', array_keys( $this->placeholders ) ) . '
' );
+ $this->form_fields = array(
+ 'enabled' => array(
+ 'title' => __( 'Enable/Disable', 'woocommerce' ),
+ 'type' => 'checkbox',
+ 'label' => __( 'Enable this email notification', 'woocommerce' ),
+ 'default' => 'yes',
+ ),
+ 'recipient' => array(
+ 'title' => __( 'Recipient(s)', 'woocommerce' ),
+ 'type' => 'text',
+ /* translators: %s: WP admin email */
+ 'description' => sprintf( __( 'Enter recipients (comma separated) for this email. Defaults to %s.', 'woocommerce' ), '' . esc_attr( get_option( 'admin_email' ) ) . '
' ),
+ 'placeholder' => '',
+ 'default' => '',
+ 'desc_tip' => true,
+ ),
+ 'subject' => array(
+ 'title' => __( 'Subject', 'woocommerce' ),
+ 'type' => 'text',
+ 'desc_tip' => true,
+ 'description' => $placeholder_text,
+ 'placeholder' => $this->get_default_subject(),
+ 'default' => '',
+ ),
+ 'heading' => array(
+ 'title' => __( 'Email heading', 'woocommerce' ),
+ 'type' => 'text',
+ 'desc_tip' => true,
+ 'description' => $placeholder_text,
+ 'placeholder' => $this->get_default_heading(),
+ 'default' => '',
+ ),
+ 'additional_content' => array(
+ 'title' => __( 'Additional content', 'woocommerce' ),
+ 'description' => __( 'Text to appear below the main email content.', 'woocommerce' ) . ' ' . $placeholder_text,
+ 'css' => 'width:400px; height: 75px;',
+ 'placeholder' => __( 'N/A', 'woocommerce' ),
+ 'type' => 'textarea',
+ 'default' => $this->get_default_additional_content(),
+ 'desc_tip' => true,
+ ),
+ 'email_type' => array(
+ 'title' => __( 'Email type', 'woocommerce' ),
+ 'type' => 'select',
+ 'description' => __( 'Choose which format of email to send.', 'woocommerce' ),
+ 'default' => 'html',
+ 'class' => 'email_type wc-enhanced-select',
+ 'options' => $this->get_email_type_options(),
+ 'desc_tip' => true,
+ ),
+ );
+ }
+ }
+
+endif;
+
+return new WC_Email_New_Order();
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email.php
new file mode 100644
index 0000000..a9c2ff3
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/emails/class-wc-email.php
@@ -0,0 +1,1080 @@
+', // Greater-than.
+ '<', // Less-than.
+ '&', // Ampersand.
+ '&', // Ampersand.
+ '(c)', // Copyright.
+ '(tm)', // Trademark.
+ '(R)', // Registered.
+ '--', // mdash.
+ '-', // ndash.
+ '*', // Bullet.
+ '£', // Pound sign.
+ 'EUR', // Euro sign. € ?.
+ '$', // Dollar sign.
+ '', // Unknown/unhandled entities.
+ ' ', // Runs of spaces, post-handling.
+ );
+
+ /**
+ * Strings to find/replace in subjects/headings.
+ *
+ * @var array
+ */
+ protected $placeholders = array();
+
+ /**
+ * Strings to find in subjects/headings.
+ *
+ * @deprecated 3.2.0 in favour of placeholders
+ * @var array
+ */
+ public $find = array();
+
+ /**
+ * Strings to replace in subjects/headings.
+ *
+ * @deprecated 3.2.0 in favour of placeholders
+ * @var array
+ */
+ public $replace = array();
+
+ /**
+ * Constructor.
+ */
+ public function __construct() {
+ // Find/replace.
+ $this->placeholders = array_merge(
+ array(
+ '{site_title}' => $this->get_blogname(),
+ '{site_address}' => wp_parse_url( home_url(), PHP_URL_HOST ),
+ '{site_url}' => wp_parse_url( home_url(), PHP_URL_HOST ),
+ ),
+ $this->placeholders
+ );
+
+ // Init settings.
+ $this->init_form_fields();
+ $this->init_settings();
+
+ // Default template base if not declared in child constructor.
+ if ( is_null( $this->template_base ) ) {
+ $this->template_base = WC()->plugin_path() . '/templates/';
+ }
+
+ $this->email_type = $this->get_option( 'email_type' );
+ $this->enabled = $this->get_option( 'enabled' );
+
+ add_action( 'phpmailer_init', array( $this, 'handle_multipart' ) );
+ add_action( 'woocommerce_update_options_email_' . $this->id, array( $this, 'process_admin_options' ) );
+ }
+
+ /**
+ * Handle multipart mail.
+ *
+ * @param PHPMailer $mailer PHPMailer object.
+ * @return PHPMailer
+ */
+ public function handle_multipart( $mailer ) {
+ if ( $this->sending && 'multipart' === $this->get_email_type() ) {
+ $mailer->AltBody = wordwrap( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
+ preg_replace( $this->plain_search, $this->plain_replace, wp_strip_all_tags( $this->get_content_plain() ) )
+ );
+ $this->sending = false;
+ }
+ return $mailer;
+ }
+
+ /**
+ * Format email string.
+ *
+ * @param mixed $string Text to replace placeholders in.
+ * @return string
+ */
+ public function format_string( $string ) {
+ $find = array_keys( $this->placeholders );
+ $replace = array_values( $this->placeholders );
+
+ // If using legacy find replace, add those to our find/replace arrays first. @todo deprecate in 4.0.0.
+ $find = array_merge( (array) $this->find, $find );
+ $replace = array_merge( (array) $this->replace, $replace );
+
+ // Take care of blogname which is no longer defined as a valid placeholder.
+ $find[] = '{blogname}';
+ $replace[] = $this->get_blogname();
+
+ // If using the older style filters for find and replace, ensure the array is associative and then pass through filters. @todo deprecate in 4.0.0.
+ if ( has_filter( 'woocommerce_email_format_string_replace' ) || has_filter( 'woocommerce_email_format_string_find' ) ) {
+ $legacy_find = $this->find;
+ $legacy_replace = $this->replace;
+
+ foreach ( $this->placeholders as $find => $replace ) {
+ $legacy_key = sanitize_title( str_replace( '_', '-', trim( $find, '{}' ) ) );
+ $legacy_find[ $legacy_key ] = $find;
+ $legacy_replace[ $legacy_key ] = $replace;
+ }
+
+ $string = str_replace( apply_filters( 'woocommerce_email_format_string_find', $legacy_find, $this ), apply_filters( 'woocommerce_email_format_string_replace', $legacy_replace, $this ), $string );
+ }
+
+ /**
+ * Filter for main find/replace.
+ *
+ * @since 3.2.0
+ */
+ return apply_filters( 'woocommerce_email_format_string', str_replace( $find, $replace, $string ), $this );
+ }
+
+ /**
+ * Set the locale to the store locale for customer emails to make sure emails are in the store language.
+ */
+ public function setup_locale() {
+ if ( $this->is_customer_email() && apply_filters( 'woocommerce_email_setup_locale', true ) ) {
+ wc_switch_to_site_locale();
+ }
+ }
+
+ /**
+ * Restore the locale to the default locale. Use after finished with setup_locale.
+ */
+ public function restore_locale() {
+ if ( $this->is_customer_email() && apply_filters( 'woocommerce_email_restore_locale', true ) ) {
+ wc_restore_locale();
+ }
+ }
+
+ /**
+ * Get email subject.
+ *
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_subject() {
+ return $this->subject;
+ }
+
+ /**
+ * Get email heading.
+ *
+ * @since 3.1.0
+ * @return string
+ */
+ public function get_default_heading() {
+ return $this->heading;
+ }
+
+ /**
+ * Default content to show below main email content.
+ *
+ * @since 3.7.0
+ * @return string
+ */
+ public function get_default_additional_content() {
+ return '';
+ }
+
+ /**
+ * Return content from the additional_content field.
+ *
+ * Displayed above the footer.
+ *
+ * @since 3.7.0
+ * @return string
+ */
+ public function get_additional_content() {
+ $content = $this->get_option( 'additional_content', '' );
+
+ return apply_filters( 'woocommerce_email_additional_content_' . $this->id, $this->format_string( $content ), $this->object, $this );
+ }
+
+ /**
+ * Get email subject.
+ *
+ * @return string
+ */
+ public function get_subject() {
+ return apply_filters( 'woocommerce_email_subject_' . $this->id, $this->format_string( $this->get_option( 'subject', $this->get_default_subject() ) ), $this->object, $this );
+ }
+
+ /**
+ * Get email heading.
+ *
+ * @return string
+ */
+ public function get_heading() {
+ return apply_filters( 'woocommerce_email_heading_' . $this->id, $this->format_string( $this->get_option( 'heading', $this->get_default_heading() ) ), $this->object, $this );
+ }
+
+ /**
+ * Get valid recipients.
+ *
+ * @return string
+ */
+ public function get_recipient() {
+ $recipient = apply_filters( 'woocommerce_email_recipient_' . $this->id, $this->recipient, $this->object, $this );
+ $recipients = array_map( 'trim', explode( ',', $recipient ) );
+ $recipients = array_filter( $recipients, 'is_email' );
+ return implode( ', ', $recipients );
+ }
+
+ /**
+ * Get email headers.
+ *
+ * @return string
+ */
+ public function get_headers() {
+ $header = 'Content-Type: ' . $this->get_content_type() . "\r\n";
+
+ if ( in_array( $this->id, array( 'new_order', 'cancelled_order', 'failed_order' ), true ) ) {
+ if ( $this->object && $this->object->get_billing_email() && ( $this->object->get_billing_first_name() || $this->object->get_billing_last_name() ) ) {
+ $header .= 'Reply-to: ' . $this->object->get_billing_first_name() . ' ' . $this->object->get_billing_last_name() . ' <' . $this->object->get_billing_email() . ">\r\n";
+ }
+ } elseif ( $this->get_from_address() && $this->get_from_name() ) {
+ $header .= 'Reply-to: ' . $this->get_from_name() . ' <' . $this->get_from_address() . ">\r\n";
+ }
+
+ return apply_filters( 'woocommerce_email_headers', $header, $this->id, $this->object, $this );
+ }
+
+ /**
+ * Get email attachments.
+ *
+ * @return array
+ */
+ public function get_attachments() {
+ return apply_filters( 'woocommerce_email_attachments', array(), $this->id, $this->object, $this );
+ }
+
+ /**
+ * Return email type.
+ *
+ * @return string
+ */
+ public function get_email_type() {
+ return $this->email_type && class_exists( 'DOMDocument' ) ? $this->email_type : 'plain';
+ }
+
+ /**
+ * Get email content type.
+ *
+ * @param string $default_content_type Default wp_mail() content type.
+ * @return string
+ */
+ public function get_content_type( $default_content_type = '' ) {
+ switch ( $this->get_email_type() ) {
+ case 'html':
+ $content_type = 'text/html';
+ break;
+ case 'multipart':
+ $content_type = 'multipart/alternative';
+ break;
+ default:
+ $content_type = 'text/plain';
+ break;
+ }
+
+ return apply_filters( 'woocommerce_email_content_type', $content_type, $this, $default_content_type );
+ }
+
+ /**
+ * Return the email's title
+ *
+ * @return string
+ */
+ public function get_title() {
+ return apply_filters( 'woocommerce_email_title', $this->title, $this );
+ }
+
+ /**
+ * Return the email's description
+ *
+ * @return string
+ */
+ public function get_description() {
+ return apply_filters( 'woocommerce_email_description', $this->description, $this );
+ }
+
+ /**
+ * Proxy to parent's get_option and attempt to localize the result using gettext.
+ *
+ * @param string $key Option key.
+ * @param mixed $empty_value Value to use when option is empty.
+ * @return string
+ */
+ public function get_option( $key, $empty_value = null ) {
+ $value = parent::get_option( $key, $empty_value );
+ return apply_filters( 'woocommerce_email_get_option', $value, $this, $value, $key, $empty_value );
+ }
+
+ /**
+ * Checks if this email is enabled and will be sent.
+ *
+ * @return bool
+ */
+ public function is_enabled() {
+ return apply_filters( 'woocommerce_email_enabled_' . $this->id, 'yes' === $this->enabled, $this->object, $this );
+ }
+
+ /**
+ * Checks if this email is manually sent
+ *
+ * @return bool
+ */
+ public function is_manual() {
+ return $this->manual;
+ }
+
+ /**
+ * Checks if this email is customer focussed.
+ *
+ * @return bool
+ */
+ public function is_customer_email() {
+ return $this->customer_email;
+ }
+
+ /**
+ * Get WordPress blog name.
+ *
+ * @return string
+ */
+ public function get_blogname() {
+ return wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
+ }
+
+ /**
+ * Get email content.
+ *
+ * @return string
+ */
+ public function get_content() {
+ $this->sending = true;
+
+ if ( 'plain' === $this->get_email_type() ) {
+ $email_content = wordwrap( preg_replace( $this->plain_search, $this->plain_replace, wp_strip_all_tags( $this->get_content_plain() ) ), 70 );
+ } else {
+ $email_content = $this->get_content_html();
+ }
+
+ return $email_content;
+ }
+
+ /**
+ * Apply inline styles to dynamic content.
+ *
+ * We only inline CSS for html emails, and to do so we use Emogrifier library (if supported).
+ *
+ * @version 4.0.0
+ * @param string|null $content Content that will receive inline styles.
+ * @return string
+ */
+ public function style_inline( $content ) {
+ if ( in_array( $this->get_content_type(), array( 'text/html', 'multipart/alternative' ), true ) ) {
+ ob_start();
+ wc_get_template( 'emails/email-styles.php' );
+ $css = apply_filters( 'woocommerce_email_styles', ob_get_clean(), $this );
+
+ $emogrifier_class = 'Pelago\\Emogrifier';
+
+ if ( $this->supports_emogrifier() && class_exists( $emogrifier_class ) ) {
+ try {
+ $emogrifier = new $emogrifier_class( $content, $css );
+
+ do_action( 'woocommerce_emogrifier', $emogrifier, $this );
+
+ $content = $emogrifier->emogrify();
+ $html_prune = \Pelago\Emogrifier\HtmlProcessor\HtmlPruner::fromHtml( $content );
+ $html_prune->removeElementsWithDisplayNone();
+ $content = $html_prune->render();
+ } catch ( Exception $e ) {
+ $logger = wc_get_logger();
+ $logger->error( $e->getMessage(), array( 'source' => 'emogrifier' ) );
+ }
+ } else {
+ $content = '' . $content;
+ }
+ }
+
+ return $content;
+ }
+
+ /**
+ * Return if emogrifier library is supported.
+ *
+ * @version 4.0.0
+ * @since 3.5.0
+ * @return bool
+ */
+ protected function supports_emogrifier() {
+ return class_exists( 'DOMDocument' );
+ }
+
+ /**
+ * Get the email content in plain text format.
+ *
+ * @return string
+ */
+ public function get_content_plain() {
+ return ''; }
+
+ /**
+ * Get the email content in HTML format.
+ *
+ * @return string
+ */
+ public function get_content_html() {
+ return ''; }
+
+ /**
+ * Get the from name for outgoing emails.
+ *
+ * @param string $from_name Default wp_mail() name associated with the "from" email address.
+ * @return string
+ */
+ public function get_from_name( $from_name = '' ) {
+ $from_name = apply_filters( 'woocommerce_email_from_name', get_option( 'woocommerce_email_from_name' ), $this, $from_name );
+ return wp_specialchars_decode( esc_html( $from_name ), ENT_QUOTES );
+ }
+
+ /**
+ * Get the from address for outgoing emails.
+ *
+ * @param string $from_email Default wp_mail() email address to send from.
+ * @return string
+ */
+ public function get_from_address( $from_email = '' ) {
+ $from_email = apply_filters( 'woocommerce_email_from_address', get_option( 'woocommerce_email_from_address' ), $this, $from_email );
+ return sanitize_email( $from_email );
+ }
+
+ /**
+ * Send an email.
+ *
+ * @param string $to Email to.
+ * @param string $subject Email subject.
+ * @param string $message Email message.
+ * @param string $headers Email headers.
+ * @param array $attachments Email attachments.
+ * @return bool success
+ */
+ public function send( $to, $subject, $message, $headers, $attachments ) {
+ add_filter( 'wp_mail_from', array( $this, 'get_from_address' ) );
+ add_filter( 'wp_mail_from_name', array( $this, 'get_from_name' ) );
+ add_filter( 'wp_mail_content_type', array( $this, 'get_content_type' ) );
+
+ $message = apply_filters( 'woocommerce_mail_content', $this->style_inline( $message ) );
+ $mail_callback = apply_filters( 'woocommerce_mail_callback', 'wp_mail', $this );
+ $mail_callback_params = apply_filters( 'woocommerce_mail_callback_params', array( $to, $subject, $message, $headers, $attachments ), $this );
+ $return = $mail_callback( ...$mail_callback_params );
+
+ remove_filter( 'wp_mail_from', array( $this, 'get_from_address' ) );
+ remove_filter( 'wp_mail_from_name', array( $this, 'get_from_name' ) );
+ remove_filter( 'wp_mail_content_type', array( $this, 'get_content_type' ) );
+
+ return $return;
+ }
+
+ /**
+ * Initialise Settings Form Fields - these are generic email options most will use.
+ */
+ public function init_form_fields() {
+ /* translators: %s: list of placeholders */
+ $placeholder_text = sprintf( __( 'Available placeholders: %s', 'woocommerce' ), '' . esc_html( implode( '
, ', array_keys( $this->placeholders ) ) ) . '
' );
+ $this->form_fields = array(
+ 'enabled' => array(
+ 'title' => __( 'Enable/Disable', 'woocommerce' ),
+ 'type' => 'checkbox',
+ 'label' => __( 'Enable this email notification', 'woocommerce' ),
+ 'default' => 'yes',
+ ),
+ 'subject' => array(
+ 'title' => __( 'Subject', 'woocommerce' ),
+ 'type' => 'text',
+ 'desc_tip' => true,
+ 'description' => $placeholder_text,
+ 'placeholder' => $this->get_default_subject(),
+ 'default' => '',
+ ),
+ 'heading' => array(
+ 'title' => __( 'Email heading', 'woocommerce' ),
+ 'type' => 'text',
+ 'desc_tip' => true,
+ 'description' => $placeholder_text,
+ 'placeholder' => $this->get_default_heading(),
+ 'default' => '',
+ ),
+ 'additional_content' => array(
+ 'title' => __( 'Additional content', 'woocommerce' ),
+ 'description' => __( 'Text to appear below the main email content.', 'woocommerce' ) . ' ' . $placeholder_text,
+ 'css' => 'width:400px; height: 75px;',
+ 'placeholder' => __( 'N/A', 'woocommerce' ),
+ 'type' => 'textarea',
+ 'default' => $this->get_default_additional_content(),
+ 'desc_tip' => true,
+ ),
+ 'email_type' => array(
+ 'title' => __( 'Email type', 'woocommerce' ),
+ 'type' => 'select',
+ 'description' => __( 'Choose which format of email to send.', 'woocommerce' ),
+ 'default' => 'html',
+ 'class' => 'email_type wc-enhanced-select',
+ 'options' => $this->get_email_type_options(),
+ 'desc_tip' => true,
+ ),
+ );
+ }
+
+ /**
+ * Email type options.
+ *
+ * @return array
+ */
+ public function get_email_type_options() {
+ $types = array( 'plain' => __( 'Plain text', 'woocommerce' ) );
+
+ if ( class_exists( 'DOMDocument' ) ) {
+ $types['html'] = __( 'HTML', 'woocommerce' );
+ $types['multipart'] = __( 'Multipart', 'woocommerce' );
+ }
+
+ return $types;
+ }
+
+ /**
+ * Admin Panel Options Processing.
+ */
+ public function process_admin_options() {
+ // Save regular options.
+ parent::process_admin_options();
+
+ $post_data = $this->get_post_data();
+
+ // Save templates.
+ if ( isset( $post_data['template_html_code'] ) ) {
+ $this->save_template( $post_data['template_html_code'], $this->template_html );
+ }
+ if ( isset( $post_data['template_plain_code'] ) ) {
+ $this->save_template( $post_data['template_plain_code'], $this->template_plain );
+ }
+ }
+
+ /**
+ * Get template.
+ *
+ * @param string $type Template type. Can be either 'template_html' or 'template_plain'.
+ * @return string
+ */
+ public function get_template( $type ) {
+ $type = basename( $type );
+
+ if ( 'template_html' === $type ) {
+ return $this->template_html;
+ } elseif ( 'template_plain' === $type ) {
+ return $this->template_plain;
+ }
+ return '';
+ }
+
+ /**
+ * Save the email templates.
+ *
+ * @since 2.4.0
+ * @param string $template_code Template code.
+ * @param string $template_path Template path.
+ */
+ protected function save_template( $template_code, $template_path ) {
+ if ( current_user_can( 'edit_themes' ) && ! empty( $template_code ) && ! empty( $template_path ) ) {
+ $saved = false;
+ $file = get_stylesheet_directory() . '/' . WC()->template_path() . $template_path;
+ $code = wp_unslash( $template_code );
+
+ if ( is_writeable( $file ) ) { // phpcs:ignore WordPress.VIP.FileSystemWritesDisallow.file_ops_is_writeable
+ $f = fopen( $file, 'w+' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen
+
+ if ( false !== $f ) {
+ fwrite( $f, $code ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fwrite
+ fclose( $f ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose
+ $saved = true;
+ }
+ }
+
+ if ( ! $saved ) {
+ $redirect = add_query_arg( 'wc_error', rawurlencode( __( 'Could not write to template file.', 'woocommerce' ) ) );
+ wp_safe_redirect( $redirect );
+ exit;
+ }
+ }
+ }
+
+ /**
+ * Get the template file in the current theme.
+ *
+ * @param string $template Template name.
+ *
+ * @return string
+ */
+ public function get_theme_template_file( $template ) {
+ return get_stylesheet_directory() . '/' . apply_filters( 'woocommerce_template_directory', 'woocommerce', $template ) . '/' . $template;
+ }
+
+ /**
+ * Move template action.
+ *
+ * @param string $template_type Template type.
+ */
+ protected function move_template_action( $template_type ) {
+ $template = $this->get_template( $template_type );
+ if ( ! empty( $template ) ) {
+ $theme_file = $this->get_theme_template_file( $template );
+
+ if ( wp_mkdir_p( dirname( $theme_file ) ) && ! file_exists( $theme_file ) ) {
+
+ // Locate template file.
+ $core_file = $this->template_base . $template;
+ $template_file = apply_filters( 'woocommerce_locate_core_template', $core_file, $template, $this->template_base, $this->id );
+
+ // Copy template file.
+ copy( $template_file, $theme_file );
+
+ /**
+ * Action hook fired after copying email template file.
+ *
+ * @param string $template_type The copied template type
+ * @param string $email The email object
+ */
+ do_action( 'woocommerce_copy_email_template', $template_type, $this );
+
+ ?>
+ get_title() ); ?>
+
+ get_description() ) ); // phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped ?>
+
+
+
+
+ generate_settings_html(); ?>
+
+
+
+
+ template_html ) || ! empty( $this->template_plain ) ) ) {
+ ?>
+ ' . esc_html( trailingslashit( basename( get_stylesheet_directory() ) ) . $template_dir . '/' . $template ) . '
' );
+ ?>
+
+
+ $name ) {
+ if ( ! isset( $account_names[ $i ] ) ) {
+ continue;
+ }
+
+ $accounts[] = array(
+ 'account_name' => $account_names[ $i ],
+ 'account_number' => $account_numbers[ $i ],
+ 'bank_name' => $bank_names[ $i ],
+ 'sort_code' => $sort_codes[ $i ],
+ 'iban' => $ibans[ $i ],
+ 'bic' => $bics[ $i ],
+ );
+ }
+ }
+ // phpcs:enable
+
+ update_option( 'woocommerce_bacs_accounts', $accounts );
+ }
+
+ /**
+ * Output for the order received page.
+ *
+ * @param int $order_id Order ID.
+ */
+ public function thankyou_page( $order_id ) {
+
+ if ( $this->instructions ) {
+ echo wp_kses_post( wpautop( wptexturize( wp_kses_post( $this->instructions ) ) ) );
+ }
+ $this->bank_details( $order_id );
+
+ }
+
+ /**
+ * Add content to the WC emails.
+ *
+ * @param WC_Order $order Order object.
+ * @param bool $sent_to_admin Sent to admin.
+ * @param bool $plain_text Email format: plain text or HTML.
+ */
+ public function email_instructions( $order, $sent_to_admin, $plain_text = false ) {
+
+ if ( ! $sent_to_admin && 'bacs' === $order->get_payment_method() && $order->has_status( 'on-hold' ) ) {
+ if ( $this->instructions ) {
+ echo wp_kses_post( wpautop( wptexturize( $this->instructions ) ) . PHP_EOL );
+ }
+ $this->bank_details( $order->get_id() );
+ }
+
+ }
+
+ /**
+ * Get bank details and place into a list format.
+ *
+ * @param int $order_id Order ID.
+ */
+ private function bank_details( $order_id = '' ) {
+
+ if ( empty( $this->account_details ) ) {
+ return;
+ }
+
+ // Get order and store in $order.
+ $order = wc_get_order( $order_id );
+
+ // Get the order country and country $locale.
+ $country = $order->get_billing_country();
+ $locale = $this->get_country_locale();
+
+ // Get sortcode label in the $locale array and use appropriate one.
+ $sortcode = isset( $locale[ $country ]['sortcode']['label'] ) ? $locale[ $country ]['sortcode']['label'] : __( 'Sort code', 'woocommerce' );
+
+ $bacs_accounts = apply_filters( 'woocommerce_bacs_accounts', $this->account_details, $order_id );
+
+ if ( ! empty( $bacs_accounts ) ) {
+ $account_html = '';
+ $has_details = false;
+
+ foreach ( $bacs_accounts as $bacs_account ) {
+ $bacs_account = (object) $bacs_account;
+
+ if ( $bacs_account->account_name ) {
+ $account_html .= '
+
+
+
+
+ ' . wp_kses_post( wp_unslash( $bacs_account->account_name ) ) . ':
' . PHP_EOL;
+ }
+
+ $account_html .= '' . PHP_EOL;
+
+ // BACS account fields shown on the thanks page and in emails.
+ $account_fields = apply_filters(
+ 'woocommerce_bacs_account_fields',
+ array(
+ 'bank_name' => array(
+ 'label' => __( 'Bank', 'woocommerce' ),
+ 'value' => $bacs_account->bank_name,
+ ),
+ 'account_number' => array(
+ 'label' => __( 'Account number', 'woocommerce' ),
+ 'value' => $bacs_account->account_number,
+ ),
+ 'sort_code' => array(
+ 'label' => $sortcode,
+ 'value' => $bacs_account->sort_code,
+ ),
+ 'iban' => array(
+ 'label' => __( 'IBAN', 'woocommerce' ),
+ 'value' => $bacs_account->iban,
+ ),
+ 'bic' => array(
+ 'label' => __( 'BIC', 'woocommerce' ),
+ 'value' => $bacs_account->bic,
+ ),
+ ),
+ $order_id
+ );
+
+ foreach ( $account_fields as $field_key => $field ) {
+ if ( ! empty( $field['value'] ) ) {
+ $account_html .= '
';
+ }
+
+ if ( $has_details ) {
+ echo '' . esc_html__( 'Our bank details', 'woocommerce' ) . '
' . wp_kses_post( PHP_EOL . $account_html ) . '';
+ }
+
+ $icon_html .= sprintf( '' . esc_attr__( 'What is PayPal?', 'woocommerce' ) . '', esc_url( $this->get_icon_url( $base_country ) ) );
+
+ return apply_filters( 'woocommerce_gateway_icon', $icon_html, $this->id );
+ }
+
+ /**
+ * Get the link for an icon based on country.
+ *
+ * @param string $country Country two letter code.
+ * @return string
+ */
+ protected function get_icon_url( $country ) {
+ $url = 'https://www.paypal.com/' . strtolower( $country );
+ $home_counties = array( 'BE', 'CZ', 'DK', 'HU', 'IT', 'JP', 'NL', 'NO', 'ES', 'SE', 'TR', 'IN' );
+ $countries = array( 'DZ', 'AU', 'BH', 'BQ', 'BW', 'CA', 'CN', 'CW', 'FI', 'FR', 'DE', 'GR', 'HK', 'ID', 'JO', 'KE', 'KW', 'LU', 'MY', 'MA', 'OM', 'PH', 'PL', 'PT', 'QA', 'IE', 'RU', 'BL', 'SX', 'MF', 'SA', 'SG', 'SK', 'KR', 'SS', 'TW', 'TH', 'AE', 'GB', 'US', 'VN' );
+
+ if ( in_array( $country, $home_counties, true ) ) {
+ return $url . '/webapps/mpp/home';
+ } elseif ( in_array( $country, $countries, true ) ) {
+ return $url . '/webapps/mpp/paypal-popup';
+ } else {
+ return $url . '/cgi-bin/webscr?cmd=xpt/Marketing/general/WIPaypal-outside';
+ }
+ }
+
+ /**
+ * Get PayPal images for a country.
+ *
+ * @param string $country Country code.
+ * @return array of image URLs
+ */
+ protected function get_icon_image( $country ) {
+ switch ( $country ) {
+ case 'US':
+ case 'NZ':
+ case 'CZ':
+ case 'HU':
+ case 'MY':
+ $icon = 'https://www.paypalobjects.com/webstatic/mktg/logo/AM_mc_vs_dc_ae.jpg';
+ break;
+ case 'TR':
+ $icon = 'https://www.paypalobjects.com/webstatic/mktg/logo-center/logo_paypal_odeme_secenekleri.jpg';
+ break;
+ case 'GB':
+ $icon = 'https://www.paypalobjects.com/webstatic/mktg/Logo/AM_mc_vs_ms_ae_UK.png';
+ break;
+ case 'MX':
+ $icon = array(
+ 'https://www.paypal.com/es_XC/Marketing/i/banner/paypal_visa_mastercard_amex.png',
+ 'https://www.paypal.com/es_XC/Marketing/i/banner/paypal_debit_card_275x60.gif',
+ );
+ break;
+ case 'FR':
+ $icon = 'https://www.paypalobjects.com/webstatic/mktg/logo-center/logo_paypal_moyens_paiement_fr.jpg';
+ break;
+ case 'AU':
+ $icon = 'https://www.paypalobjects.com/webstatic/en_AU/mktg/logo/Solutions-graphics-1-184x80.jpg';
+ break;
+ case 'DK':
+ $icon = 'https://www.paypalobjects.com/webstatic/mktg/logo-center/logo_PayPal_betalingsmuligheder_dk.jpg';
+ break;
+ case 'RU':
+ $icon = 'https://www.paypalobjects.com/webstatic/ru_RU/mktg/business/pages/logo-center/AM_mc_vs_dc_ae.jpg';
+ break;
+ case 'NO':
+ $icon = 'https://www.paypalobjects.com/webstatic/mktg/logo-center/banner_pl_just_pp_319x110.jpg';
+ break;
+ case 'CA':
+ $icon = 'https://www.paypalobjects.com/webstatic/en_CA/mktg/logo-image/AM_mc_vs_dc_ae.jpg';
+ break;
+ case 'HK':
+ $icon = 'https://www.paypalobjects.com/webstatic/en_HK/mktg/logo/AM_mc_vs_dc_ae.jpg';
+ break;
+ case 'SG':
+ $icon = 'https://www.paypalobjects.com/webstatic/en_SG/mktg/Logos/AM_mc_vs_dc_ae.jpg';
+ break;
+ case 'TW':
+ $icon = 'https://www.paypalobjects.com/webstatic/en_TW/mktg/logos/AM_mc_vs_dc_ae.jpg';
+ break;
+ case 'TH':
+ $icon = 'https://www.paypalobjects.com/webstatic/en_TH/mktg/Logos/AM_mc_vs_dc_ae.jpg';
+ break;
+ case 'JP':
+ $icon = 'https://www.paypal.com/ja_JP/JP/i/bnr/horizontal_solution_4_jcb.gif';
+ break;
+ case 'IN':
+ $icon = 'https://www.paypalobjects.com/webstatic/mktg/logo/AM_mc_vs_dc_ae.jpg';
+ break;
+ default:
+ $icon = WC_HTTPS::force_https_url( WC()->plugin_url() . '/includes/gateways/paypal/assets/images/paypal.png' );
+ break;
+ }
+ return apply_filters( 'woocommerce_paypal_icon', $icon );
+ }
+
+ /**
+ * Check if this gateway is available in the user's country based on currency.
+ *
+ * @return bool
+ */
+ public function is_valid_for_use() {
+ return in_array(
+ get_woocommerce_currency(),
+ apply_filters(
+ 'woocommerce_paypal_supported_currencies',
+ array( 'AUD', 'BRL', 'CAD', 'MXN', 'NZD', 'HKD', 'SGD', 'USD', 'EUR', 'JPY', 'TRY', 'NOK', 'CZK', 'DKK', 'HUF', 'ILS', 'MYR', 'PHP', 'PLN', 'SEK', 'CHF', 'TWD', 'THB', 'GBP', 'RMB', 'RUB', 'INR' )
+ ),
+ true
+ );
+ }
+
+ /**
+ * Admin Panel Options.
+ * - Options for bits like 'title' and availability on a country-by-country basis.
+ *
+ * @since 1.0.0
+ */
+ public function admin_options() {
+ if ( $this->is_valid_for_use() ) {
+ parent::admin_options();
+ } else {
+ ?>
+
' . WC_Log_Handler_File::get_log_file_path( 'paypal' ) . '
' ),
+ ),
+ 'ipn_notification' => array(
+ 'title' => __( 'IPN Email Notifications', 'woocommerce' ),
+ 'type' => 'checkbox',
+ 'label' => __( 'Enable IPN email notifications', 'woocommerce' ),
+ 'default' => 'yes',
+ 'description' => __( 'Send notifications when an IPN is received from PayPal indicating refunds, chargebacks and cancellations.', 'woocommerce' ),
+ ),
+ 'receiver_email' => array(
+ 'title' => __( 'Receiver email', 'woocommerce' ),
+ 'type' => 'email',
+ 'description' => __( 'If your main PayPal email differs from the PayPal email entered above, input your main receiver email for your PayPal account here. This is used to validate IPN requests.', 'woocommerce' ),
+ 'default' => '',
+ 'desc_tip' => true,
+ 'placeholder' => 'you@youremail.com',
+ ),
+ 'identity_token' => array(
+ 'title' => __( 'PayPal identity token', 'woocommerce' ),
+ 'type' => 'text',
+ 'description' => __( 'Optionally enable "Payment Data Transfer" (Profile > Profile and Settings > My Selling Tools > Website Preferences) and then copy your identity token here. This will allow payments to be verified without the need for PayPal IPN.', 'woocommerce' ),
+ 'default' => '',
+ 'desc_tip' => true,
+ 'placeholder' => '',
+ ),
+ 'invoice_prefix' => array(
+ 'title' => __( 'Invoice prefix', 'woocommerce' ),
+ 'type' => 'text',
+ 'description' => __( 'Please enter a prefix for your invoice numbers. If you use your PayPal account for multiple stores ensure this prefix is unique as PayPal will not allow orders with the same invoice number.', 'woocommerce' ),
+ 'default' => 'WC-',
+ 'desc_tip' => true,
+ ),
+ 'send_shipping' => array(
+ 'title' => __( 'Shipping details', 'woocommerce' ),
+ 'type' => 'checkbox',
+ 'label' => __( 'Send shipping details to PayPal instead of billing.', 'woocommerce' ),
+ 'description' => __( 'PayPal allows us to send one address. If you are using PayPal for shipping labels you may prefer to send the shipping address rather than billing. Turning this option off may prevent PayPal Seller protection from applying.', 'woocommerce' ),
+ 'default' => 'yes',
+ ),
+ 'address_override' => array(
+ 'title' => __( 'Address override', 'woocommerce' ),
+ 'type' => 'checkbox',
+ 'label' => __( 'Enable "address_override" to prevent address information from being changed.', 'woocommerce' ),
+ 'description' => __( 'PayPal verifies addresses therefore this setting can cause errors (we recommend keeping it disabled).', 'woocommerce' ),
+ 'default' => 'no',
+ ),
+ 'paymentaction' => array(
+ 'title' => __( 'Payment action', 'woocommerce' ),
+ 'type' => 'select',
+ 'class' => 'wc-enhanced-select',
+ 'description' => __( 'Choose whether you wish to capture funds immediately or authorize payment only.', 'woocommerce' ),
+ 'default' => 'sale',
+ 'desc_tip' => true,
+ 'options' => array(
+ 'sale' => __( 'Capture', 'woocommerce' ),
+ 'authorization' => __( 'Authorize', 'woocommerce' ),
+ ),
+ ),
+ 'page_style' => array(
+ 'title' => __( 'Page style', 'woocommerce' ),
+ 'type' => 'text',
+ 'description' => __( 'Optionally enter the name of the page style you wish to use. These are defined within your PayPal account. This affects classic PayPal checkout screens.', 'woocommerce' ),
+ 'default' => '',
+ 'desc_tip' => true,
+ 'placeholder' => __( 'Optional', 'woocommerce' ),
+ ),
+ 'image_url' => array(
+ 'title' => __( 'Image url', 'woocommerce' ),
+ 'type' => 'text',
+ 'description' => __( 'Optionally enter the URL to a 150x50px image displayed as your logo in the upper left corner of the PayPal checkout pages.', 'woocommerce' ),
+ 'default' => '',
+ 'desc_tip' => true,
+ 'placeholder' => __( 'Optional', 'woocommerce' ),
+ ),
+ 'api_details' => array(
+ 'title' => __( 'API credentials', 'woocommerce' ),
+ 'type' => 'title',
+ /* translators: %s: URL */
+ 'description' => sprintf( __( 'Enter your PayPal API credentials to process refunds via PayPal. Learn how to access your PayPal API Credentials.', 'woocommerce' ), 'https://developer.paypal.com/webapps/developer/docs/classic/api/apiCredentials/#create-an-api-signature' ),
+ ),
+ 'api_username' => array(
+ 'title' => __( 'Live API username', 'woocommerce' ),
+ 'type' => 'text',
+ 'description' => __( 'Get your API credentials from PayPal.', 'woocommerce' ),
+ 'default' => '',
+ 'desc_tip' => true,
+ 'placeholder' => __( 'Optional', 'woocommerce' ),
+ ),
+ 'api_password' => array(
+ 'title' => __( 'Live API password', 'woocommerce' ),
+ 'type' => 'password',
+ 'description' => __( 'Get your API credentials from PayPal.', 'woocommerce' ),
+ 'default' => '',
+ 'desc_tip' => true,
+ 'placeholder' => __( 'Optional', 'woocommerce' ),
+ ),
+ 'api_signature' => array(
+ 'title' => __( 'Live API signature', 'woocommerce' ),
+ 'type' => 'password',
+ 'description' => __( 'Get your API credentials from PayPal.', 'woocommerce' ),
+ 'default' => '',
+ 'desc_tip' => true,
+ 'placeholder' => __( 'Optional', 'woocommerce' ),
+ ),
+ 'sandbox_api_username' => array(
+ 'title' => __( 'Sandbox API username', 'woocommerce' ),
+ 'type' => 'text',
+ 'description' => __( 'Get your API credentials from PayPal.', 'woocommerce' ),
+ 'default' => '',
+ 'desc_tip' => true,
+ 'placeholder' => __( 'Optional', 'woocommerce' ),
+ ),
+ 'sandbox_api_password' => array(
+ 'title' => __( 'Sandbox API password', 'woocommerce' ),
+ 'type' => 'password',
+ 'description' => __( 'Get your API credentials from PayPal.', 'woocommerce' ),
+ 'default' => '',
+ 'desc_tip' => true,
+ 'placeholder' => __( 'Optional', 'woocommerce' ),
+ ),
+ 'sandbox_api_signature' => array(
+ 'title' => __( 'Sandbox API signature', 'woocommerce' ),
+ 'type' => 'password',
+ 'description' => __( 'Get your API credentials from PayPal.', 'woocommerce' ),
+ 'default' => '',
+ 'desc_tip' => true,
+ 'placeholder' => __( 'Optional', 'woocommerce' ),
+ ),
+);
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/import/abstract-wc-product-importer.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/import/abstract-wc-product-importer.php
new file mode 100644
index 0000000..075506f
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/import/abstract-wc-product-importer.php
@@ -0,0 +1,814 @@
+raw_keys;
+ }
+
+ /**
+ * Get file mapped headers.
+ *
+ * @return array
+ */
+ public function get_mapped_keys() {
+ return ! empty( $this->mapped_keys ) ? $this->mapped_keys : $this->raw_keys;
+ }
+
+ /**
+ * Get raw data.
+ *
+ * @return array
+ */
+ public function get_raw_data() {
+ return $this->raw_data;
+ }
+
+ /**
+ * Get parsed data.
+ *
+ * @return array
+ */
+ public function get_parsed_data() {
+ /**
+ * Filter product importer parsed data.
+ *
+ * @param array $parsed_data Parsed data.
+ * @param WC_Product_Importer $importer Importer instance.
+ */
+ return apply_filters( 'woocommerce_product_importer_parsed_data', $this->parsed_data, $this );
+ }
+
+ /**
+ * Get importer parameters.
+ *
+ * @return array
+ */
+ public function get_params() {
+ return $this->params;
+ }
+
+ /**
+ * Get file pointer position from the last read.
+ *
+ * @return int
+ */
+ public function get_file_position() {
+ return $this->file_position;
+ }
+
+ /**
+ * Get file pointer position as a percentage of file size.
+ *
+ * @return int
+ */
+ public function get_percent_complete() {
+ $size = filesize( $this->file );
+ if ( ! $size ) {
+ return 0;
+ }
+
+ return absint( min( NumberUtil::round( ( $this->file_position / $size ) * 100 ), 100 ) );
+ }
+
+ /**
+ * Prepare a single product for create or update.
+ *
+ * @param array $data Item data.
+ * @return WC_Product|WP_Error
+ */
+ protected function get_product_object( $data ) {
+ $id = isset( $data['id'] ) ? absint( $data['id'] ) : 0;
+
+ // Type is the most important part here because we need to be using the correct class and methods.
+ if ( isset( $data['type'] ) ) {
+ $types = array_keys( wc_get_product_types() );
+ $types[] = 'variation';
+
+ if ( ! in_array( $data['type'], $types, true ) ) {
+ return new WP_Error( 'woocommerce_product_importer_invalid_type', __( 'Invalid product type.', 'woocommerce' ), array( 'status' => 401 ) );
+ }
+
+ try {
+ // Prevent getting "variation_invalid_id" error message from Variation Data Store.
+ if ( 'variation' === $data['type'] ) {
+ $id = wp_update_post(
+ array(
+ 'ID' => $id,
+ 'post_type' => 'product_variation',
+ )
+ );
+ }
+
+ $product = wc_get_product_object( $data['type'], $id );
+ } catch ( WC_Data_Exception $e ) {
+ return new WP_Error( 'woocommerce_product_csv_importer_' . $e->getErrorCode(), $e->getMessage(), array( 'status' => 401 ) );
+ }
+ } elseif ( ! empty( $data['id'] ) ) {
+ $product = wc_get_product( $id );
+
+ if ( ! $product ) {
+ return new WP_Error(
+ 'woocommerce_product_csv_importer_invalid_id',
+ /* translators: %d: product ID */
+ sprintf( __( 'Invalid product ID %d.', 'woocommerce' ), $id ),
+ array(
+ 'id' => $id,
+ 'status' => 401,
+ )
+ );
+ }
+ } else {
+ $product = wc_get_product_object( 'simple', $id );
+ }
+
+ return apply_filters( 'woocommerce_product_import_get_product_object', $product, $data );
+ }
+
+ /**
+ * Process a single item and save.
+ *
+ * @throws Exception If item cannot be processed.
+ * @param array $data Raw CSV data.
+ * @return array|WP_Error
+ */
+ protected function process_item( $data ) {
+ try {
+ do_action( 'woocommerce_product_import_before_process_item', $data );
+ $data = apply_filters( 'woocommerce_product_import_process_item_data', $data );
+
+ // Get product ID from SKU if created during the importation.
+ if ( empty( $data['id'] ) && ! empty( $data['sku'] ) ) {
+ $product_id = wc_get_product_id_by_sku( $data['sku'] );
+
+ if ( $product_id ) {
+ $data['id'] = $product_id;
+ }
+ }
+
+ $object = $this->get_product_object( $data );
+ $updating = false;
+
+ if ( is_wp_error( $object ) ) {
+ return $object;
+ }
+
+ if ( $object->get_id() && 'importing' !== $object->get_status() ) {
+ $updating = true;
+ }
+
+ if ( 'external' === $object->get_type() ) {
+ unset( $data['manage_stock'], $data['stock_status'], $data['backorders'], $data['low_stock_amount'] );
+ }
+
+ if ( 'variation' === $object->get_type() ) {
+ if ( isset( $data['status'] ) && -1 === $data['status'] ) {
+ $data['status'] = 0; // Variations cannot be drafts - set to private.
+ }
+ }
+
+ if ( 'importing' === $object->get_status() ) {
+ $object->set_status( 'publish' );
+ $object->set_slug( '' );
+ }
+
+ $result = $object->set_props( array_diff_key( $data, array_flip( array( 'meta_data', 'raw_image_id', 'raw_gallery_image_ids', 'raw_attributes' ) ) ) );
+
+ if ( is_wp_error( $result ) ) {
+ throw new Exception( $result->get_error_message() );
+ }
+
+ if ( 'variation' === $object->get_type() ) {
+ $this->set_variation_data( $object, $data );
+ } else {
+ $this->set_product_data( $object, $data );
+ }
+
+ $this->set_image_data( $object, $data );
+ $this->set_meta_data( $object, $data );
+
+ $object = apply_filters( 'woocommerce_product_import_pre_insert_product_object', $object, $data );
+ $object->save();
+
+ do_action( 'woocommerce_product_import_inserted_product_object', $object, $data );
+
+ return array(
+ 'id' => $object->get_id(),
+ 'updated' => $updating,
+ );
+ } catch ( Exception $e ) {
+ return new WP_Error( 'woocommerce_product_importer_error', $e->getMessage(), array( 'status' => $e->getCode() ) );
+ }
+ }
+
+ /**
+ * Convert raw image URLs to IDs and set.
+ *
+ * @param WC_Product $product Product instance.
+ * @param array $data Item data.
+ */
+ protected function set_image_data( &$product, $data ) {
+ // Image URLs need converting to IDs before inserting.
+ if ( isset( $data['raw_image_id'] ) ) {
+ $product->set_image_id( $this->get_attachment_id_from_url( $data['raw_image_id'], $product->get_id() ) );
+ }
+
+ // Gallery image URLs need converting to IDs before inserting.
+ if ( isset( $data['raw_gallery_image_ids'] ) ) {
+ $gallery_image_ids = array();
+
+ foreach ( $data['raw_gallery_image_ids'] as $image_id ) {
+ $gallery_image_ids[] = $this->get_attachment_id_from_url( $image_id, $product->get_id() );
+ }
+ $product->set_gallery_image_ids( $gallery_image_ids );
+ }
+ }
+
+ /**
+ * Append meta data.
+ *
+ * @param WC_Product $product Product instance.
+ * @param array $data Item data.
+ */
+ protected function set_meta_data( &$product, $data ) {
+ if ( isset( $data['meta_data'] ) ) {
+ foreach ( $data['meta_data'] as $meta ) {
+ $product->update_meta_data( $meta['key'], $meta['value'] );
+ }
+ }
+ }
+
+ /**
+ * Set product data.
+ *
+ * @param WC_Product $product Product instance.
+ * @param array $data Item data.
+ * @throws Exception If data cannot be set.
+ */
+ protected function set_product_data( &$product, $data ) {
+ if ( isset( $data['raw_attributes'] ) ) {
+ $attributes = array();
+ $default_attributes = array();
+ $existing_attributes = $product->get_attributes();
+
+ foreach ( $data['raw_attributes'] as $position => $attribute ) {
+ $attribute_id = 0;
+
+ // Get ID if is a global attribute.
+ if ( ! empty( $attribute['taxonomy'] ) ) {
+ $attribute_id = $this->get_attribute_taxonomy_id( $attribute['name'] );
+ }
+
+ // Set attribute visibility.
+ if ( isset( $attribute['visible'] ) ) {
+ $is_visible = $attribute['visible'];
+ } else {
+ $is_visible = 1;
+ }
+
+ // Get name.
+ $attribute_name = $attribute_id ? wc_attribute_taxonomy_name_by_id( $attribute_id ) : $attribute['name'];
+
+ // Set if is a variation attribute based on existing attributes if possible so updates via CSV do not change this.
+ $is_variation = 0;
+
+ if ( $existing_attributes ) {
+ foreach ( $existing_attributes as $existing_attribute ) {
+ if ( $existing_attribute->get_name() === $attribute_name ) {
+ $is_variation = $existing_attribute->get_variation();
+ break;
+ }
+ }
+ }
+
+ if ( $attribute_id ) {
+ if ( isset( $attribute['value'] ) ) {
+ $options = array_map( 'wc_sanitize_term_text_based', $attribute['value'] );
+ $options = array_filter( $options, 'strlen' );
+ } else {
+ $options = array();
+ }
+
+ // Check for default attributes and set "is_variation".
+ if ( ! empty( $attribute['default'] ) && in_array( $attribute['default'], $options, true ) ) {
+ $default_term = get_term_by( 'name', $attribute['default'], $attribute_name );
+
+ if ( $default_term && ! is_wp_error( $default_term ) ) {
+ $default = $default_term->slug;
+ } else {
+ $default = sanitize_title( $attribute['default'] );
+ }
+
+ $default_attributes[ $attribute_name ] = $default;
+ $is_variation = 1;
+ }
+
+ if ( ! empty( $options ) ) {
+ $attribute_object = new WC_Product_Attribute();
+ $attribute_object->set_id( $attribute_id );
+ $attribute_object->set_name( $attribute_name );
+ $attribute_object->set_options( $options );
+ $attribute_object->set_position( $position );
+ $attribute_object->set_visible( $is_visible );
+ $attribute_object->set_variation( $is_variation );
+ $attributes[] = $attribute_object;
+ }
+ } elseif ( isset( $attribute['value'] ) ) {
+ // Check for default attributes and set "is_variation".
+ if ( ! empty( $attribute['default'] ) && in_array( $attribute['default'], $attribute['value'], true ) ) {
+ $default_attributes[ sanitize_title( $attribute['name'] ) ] = $attribute['default'];
+ $is_variation = 1;
+ }
+
+ $attribute_object = new WC_Product_Attribute();
+ $attribute_object->set_name( $attribute['name'] );
+ $attribute_object->set_options( $attribute['value'] );
+ $attribute_object->set_position( $position );
+ $attribute_object->set_visible( $is_visible );
+ $attribute_object->set_variation( $is_variation );
+ $attributes[] = $attribute_object;
+ }
+ }
+
+ $product->set_attributes( $attributes );
+
+ // Set variable default attributes.
+ if ( $product->is_type( 'variable' ) ) {
+ $product->set_default_attributes( $default_attributes );
+ }
+ }
+ }
+
+ /**
+ * Set variation data.
+ *
+ * @param WC_Product $variation Product instance.
+ * @param array $data Item data.
+ * @return WC_Product|WP_Error
+ * @throws Exception If data cannot be set.
+ */
+ protected function set_variation_data( &$variation, $data ) {
+ $parent = false;
+
+ // Check if parent exist.
+ if ( isset( $data['parent_id'] ) ) {
+ $parent = wc_get_product( $data['parent_id'] );
+
+ if ( $parent ) {
+ $variation->set_parent_id( $parent->get_id() );
+ }
+ }
+
+ // Stop if parent does not exists.
+ if ( ! $parent ) {
+ return new WP_Error( 'woocommerce_product_importer_missing_variation_parent_id', __( 'Variation cannot be imported: Missing parent ID or parent does not exist yet.', 'woocommerce' ), array( 'status' => 401 ) );
+ }
+
+ // Stop if parent is a product variation.
+ if ( $parent->is_type( 'variation' ) ) {
+ return new WP_Error( 'woocommerce_product_importer_parent_set_as_variation', __( 'Variation cannot be imported: Parent product cannot be a product variation', 'woocommerce' ), array( 'status' => 401 ) );
+ }
+
+ if ( isset( $data['raw_attributes'] ) ) {
+ $attributes = array();
+ $parent_attributes = $this->get_variation_parent_attributes( $data['raw_attributes'], $parent );
+
+ foreach ( $data['raw_attributes'] as $attribute ) {
+ $attribute_id = 0;
+
+ // Get ID if is a global attribute.
+ if ( ! empty( $attribute['taxonomy'] ) ) {
+ $attribute_id = $this->get_attribute_taxonomy_id( $attribute['name'] );
+ }
+
+ if ( $attribute_id ) {
+ $attribute_name = wc_attribute_taxonomy_name_by_id( $attribute_id );
+ } else {
+ $attribute_name = sanitize_title( $attribute['name'] );
+ }
+
+ if ( ! isset( $parent_attributes[ $attribute_name ] ) || ! $parent_attributes[ $attribute_name ]->get_variation() ) {
+ continue;
+ }
+
+ $attribute_key = sanitize_title( $parent_attributes[ $attribute_name ]->get_name() );
+ $attribute_value = isset( $attribute['value'] ) ? current( $attribute['value'] ) : '';
+
+ if ( $parent_attributes[ $attribute_name ]->is_taxonomy() ) {
+ // If dealing with a taxonomy, we need to get the slug from the name posted to the API.
+ $term = get_term_by( 'name', $attribute_value, $attribute_name );
+
+ if ( $term && ! is_wp_error( $term ) ) {
+ $attribute_value = $term->slug;
+ } else {
+ $attribute_value = sanitize_title( $attribute_value );
+ }
+ }
+
+ $attributes[ $attribute_key ] = $attribute_value;
+ }
+
+ $variation->set_attributes( $attributes );
+ }
+ }
+
+ /**
+ * Get variation parent attributes and set "is_variation".
+ *
+ * @param array $attributes Attributes list.
+ * @param WC_Product $parent Parent product data.
+ * @return array
+ */
+ protected function get_variation_parent_attributes( $attributes, $parent ) {
+ $parent_attributes = $parent->get_attributes();
+ $require_save = false;
+
+ foreach ( $attributes as $attribute ) {
+ $attribute_id = 0;
+
+ // Get ID if is a global attribute.
+ if ( ! empty( $attribute['taxonomy'] ) ) {
+ $attribute_id = $this->get_attribute_taxonomy_id( $attribute['name'] );
+ }
+
+ if ( $attribute_id ) {
+ $attribute_name = wc_attribute_taxonomy_name_by_id( $attribute_id );
+ } else {
+ $attribute_name = sanitize_title( $attribute['name'] );
+ }
+
+ // Check if attribute handle variations.
+ if ( isset( $parent_attributes[ $attribute_name ] ) && ! $parent_attributes[ $attribute_name ]->get_variation() ) {
+ // Re-create the attribute to CRUD save and generate again.
+ $parent_attributes[ $attribute_name ] = clone $parent_attributes[ $attribute_name ];
+ $parent_attributes[ $attribute_name ]->set_variation( 1 );
+
+ $require_save = true;
+ }
+ }
+
+ // Save variation attributes.
+ if ( $require_save ) {
+ $parent->set_attributes( array_values( $parent_attributes ) );
+ $parent->save();
+ }
+
+ return $parent_attributes;
+ }
+
+ /**
+ * Get attachment ID.
+ *
+ * @param string $url Attachment URL.
+ * @param int $product_id Product ID.
+ * @return int
+ * @throws Exception If attachment cannot be loaded.
+ */
+ public function get_attachment_id_from_url( $url, $product_id ) {
+ if ( empty( $url ) ) {
+ return 0;
+ }
+
+ $id = 0;
+ $upload_dir = wp_upload_dir( null, false );
+ $base_url = $upload_dir['baseurl'] . '/';
+
+ // Check first if attachment is inside the WordPress uploads directory, or we're given a filename only.
+ if ( false !== strpos( $url, $base_url ) || false === strpos( $url, '://' ) ) {
+ // Search for yyyy/mm/slug.extension or slug.extension - remove the base URL.
+ $file = str_replace( $base_url, '', $url );
+ $args = array(
+ 'post_type' => 'attachment',
+ 'post_status' => 'any',
+ 'fields' => 'ids',
+ 'meta_query' => array( // @codingStandardsIgnoreLine.
+ 'relation' => 'OR',
+ array(
+ 'key' => '_wp_attached_file',
+ 'value' => '^' . $file,
+ 'compare' => 'REGEXP',
+ ),
+ array(
+ 'key' => '_wp_attached_file',
+ 'value' => '/' . $file,
+ 'compare' => 'LIKE',
+ ),
+ array(
+ 'key' => '_wc_attachment_source',
+ 'value' => '/' . $file,
+ 'compare' => 'LIKE',
+ ),
+ ),
+ );
+ } else {
+ // This is an external URL, so compare to source.
+ $args = array(
+ 'post_type' => 'attachment',
+ 'post_status' => 'any',
+ 'fields' => 'ids',
+ 'meta_query' => array( // @codingStandardsIgnoreLine.
+ array(
+ 'value' => $url,
+ 'key' => '_wc_attachment_source',
+ ),
+ ),
+ );
+ }
+
+ $ids = get_posts( $args ); // @codingStandardsIgnoreLine.
+
+ if ( $ids ) {
+ $id = current( $ids );
+ }
+
+ // Upload if attachment does not exists.
+ if ( ! $id && stristr( $url, '://' ) ) {
+ $upload = wc_rest_upload_image_from_url( $url );
+
+ if ( is_wp_error( $upload ) ) {
+ throw new Exception( $upload->get_error_message(), 400 );
+ }
+
+ $id = wc_rest_set_uploaded_image_as_attachment( $upload, $product_id );
+
+ if ( ! wp_attachment_is_image( $id ) ) {
+ /* translators: %s: image URL */
+ throw new Exception( sprintf( __( 'Not able to attach "%s".', 'woocommerce' ), $url ), 400 );
+ }
+
+ // Save attachment source for future reference.
+ update_post_meta( $id, '_wc_attachment_source', $url );
+ }
+
+ if ( ! $id ) {
+ /* translators: %s: image URL */
+ throw new Exception( sprintf( __( 'Unable to use image "%s".', 'woocommerce' ), $url ), 400 );
+ }
+
+ return $id;
+ }
+
+ /**
+ * Get attribute taxonomy ID from the imported data.
+ * If does not exists register a new attribute.
+ *
+ * @param string $raw_name Attribute name.
+ * @return int
+ * @throws Exception If taxonomy cannot be loaded.
+ */
+ public function get_attribute_taxonomy_id( $raw_name ) {
+ global $wpdb, $wc_product_attributes;
+
+ // These are exported as labels, so convert the label to a name if possible first.
+ $attribute_labels = wp_list_pluck( wc_get_attribute_taxonomies(), 'attribute_label', 'attribute_name' );
+ $attribute_name = array_search( $raw_name, $attribute_labels, true );
+
+ if ( ! $attribute_name ) {
+ $attribute_name = wc_sanitize_taxonomy_name( $raw_name );
+ }
+
+ $attribute_id = wc_attribute_taxonomy_id_by_name( $attribute_name );
+
+ // Get the ID from the name.
+ if ( $attribute_id ) {
+ return $attribute_id;
+ }
+
+ // If the attribute does not exist, create it.
+ $attribute_id = wc_create_attribute(
+ array(
+ 'name' => $raw_name,
+ 'slug' => $attribute_name,
+ 'type' => 'select',
+ 'order_by' => 'menu_order',
+ 'has_archives' => false,
+ )
+ );
+
+ if ( is_wp_error( $attribute_id ) ) {
+ throw new Exception( $attribute_id->get_error_message(), 400 );
+ }
+
+ // Register as taxonomy while importing.
+ $taxonomy_name = wc_attribute_taxonomy_name( $attribute_name );
+ register_taxonomy(
+ $taxonomy_name,
+ apply_filters( 'woocommerce_taxonomy_objects_' . $taxonomy_name, array( 'product' ) ),
+ apply_filters(
+ 'woocommerce_taxonomy_args_' . $taxonomy_name,
+ array(
+ 'labels' => array(
+ 'name' => $raw_name,
+ ),
+ 'hierarchical' => true,
+ 'show_ui' => false,
+ 'query_var' => true,
+ 'rewrite' => false,
+ )
+ )
+ );
+
+ // Set product attributes global.
+ $wc_product_attributes = array();
+
+ foreach ( wc_get_attribute_taxonomies() as $taxonomy ) {
+ $wc_product_attributes[ wc_attribute_taxonomy_name( $taxonomy->attribute_name ) ] = $taxonomy;
+ }
+
+ return $attribute_id;
+ }
+
+ /**
+ * Memory exceeded
+ *
+ * Ensures the batch process never exceeds 90%
+ * of the maximum WordPress memory.
+ *
+ * @return bool
+ */
+ protected function memory_exceeded() {
+ $memory_limit = $this->get_memory_limit() * 0.9; // 90% of max memory
+ $current_memory = memory_get_usage( true );
+ $return = false;
+ if ( $current_memory >= $memory_limit ) {
+ $return = true;
+ }
+ return apply_filters( 'woocommerce_product_importer_memory_exceeded', $return );
+ }
+
+ /**
+ * Get memory limit
+ *
+ * @return int
+ */
+ protected function get_memory_limit() {
+ if ( function_exists( 'ini_get' ) ) {
+ $memory_limit = ini_get( 'memory_limit' );
+ } else {
+ // Sensible default.
+ $memory_limit = '128M';
+ }
+
+ if ( ! $memory_limit || -1 === intval( $memory_limit ) ) {
+ // Unlimited, set to 32GB.
+ $memory_limit = '32000M';
+ }
+ return intval( $memory_limit ) * 1024 * 1024;
+ }
+
+ /**
+ * Time exceeded.
+ *
+ * Ensures the batch never exceeds a sensible time limit.
+ * A timeout limit of 30s is common on shared hosting.
+ *
+ * @return bool
+ */
+ protected function time_exceeded() {
+ $finish = $this->start_time + apply_filters( 'woocommerce_product_importer_default_time_limit', 20 ); // 20 seconds
+ $return = false;
+ if ( time() >= $finish ) {
+ $return = true;
+ }
+ return apply_filters( 'woocommerce_product_importer_time_exceeded', $return );
+ }
+
+ /**
+ * Explode CSV cell values using commas by default, and handling escaped
+ * separators.
+ *
+ * @since 3.2.0
+ * @param string $value Value to explode.
+ * @param string $separator Separator separating each value. Defaults to comma.
+ * @return array
+ */
+ protected function explode_values( $value, $separator = ',' ) {
+ $value = str_replace( '\\,', '::separator::', $value );
+ $values = explode( $separator, $value );
+ $values = array_map( array( $this, 'explode_values_formatter' ), $values );
+
+ return $values;
+ }
+
+ /**
+ * Remove formatting and trim each value.
+ *
+ * @since 3.2.0
+ * @param string $value Value to format.
+ * @return string
+ */
+ protected function explode_values_formatter( $value ) {
+ return trim( str_replace( '::separator::', ',', $value ) );
+ }
+
+ /**
+ * The exporter prepends a ' to escape fields that start with =, +, - or @.
+ * Remove the prepended ' character preceding those characters.
+ *
+ * @since 3.5.2
+ * @param string $value A string that may or may not have been escaped with '.
+ * @return string
+ */
+ protected function unescape_data( $value ) {
+ $active_content_triggers = array( "'=", "'+", "'-", "'@" );
+
+ if ( in_array( mb_substr( $value, 0, 2 ), $active_content_triggers, true ) ) {
+ $value = mb_substr( $value, 1 );
+ }
+
+ return $value;
+ }
+
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/import/class-wc-product-csv-importer.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/import/class-wc-product-csv-importer.php
new file mode 100644
index 0000000..c9c11f4
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/import/class-wc-product-csv-importer.php
@@ -0,0 +1,1128 @@
+ 0, // File pointer start.
+ 'end_pos' => -1, // File pointer end.
+ 'lines' => -1, // Max lines to read.
+ 'mapping' => array(), // Column mapping. csv_heading => schema_heading.
+ 'parse' => false, // Whether to sanitize and format data.
+ 'update_existing' => false, // Whether to update existing items.
+ 'delimiter' => ',', // CSV delimiter.
+ 'prevent_timeouts' => true, // Check memory and time usage and abort if reaching limit.
+ 'enclosure' => '"', // The character used to wrap text in the CSV.
+ 'escape' => "\0", // PHP uses '\' as the default escape character. This is not RFC-4180 compliant. This disables the escape character.
+ );
+
+ $this->params = wp_parse_args( $params, $default_args );
+ $this->file = $file;
+
+ if ( isset( $this->params['mapping']['from'], $this->params['mapping']['to'] ) ) {
+ $this->params['mapping'] = array_combine( $this->params['mapping']['from'], $this->params['mapping']['to'] );
+ }
+
+ // Import mappings for CSV data.
+ include_once dirname( dirname( __FILE__ ) ) . '/admin/importers/mappings/mappings.php';
+
+ $this->read_file();
+ }
+
+ /**
+ * Read file.
+ */
+ protected function read_file() {
+ if ( ! WC_Product_CSV_Importer_Controller::is_file_valid_csv( $this->file ) ) {
+ wp_die( esc_html__( 'Invalid file type. The importer supports CSV and TXT file formats.', 'woocommerce' ) );
+ }
+
+ $handle = fopen( $this->file, 'r' ); // @codingStandardsIgnoreLine.
+
+ if ( false !== $handle ) {
+ $this->raw_keys = version_compare( PHP_VERSION, '5.3', '>=' ) ? array_map( 'trim', fgetcsv( $handle, 0, $this->params['delimiter'], $this->params['enclosure'], $this->params['escape'] ) ) : array_map( 'trim', fgetcsv( $handle, 0, $this->params['delimiter'], $this->params['enclosure'] ) ); // @codingStandardsIgnoreLine
+
+ // Remove BOM signature from the first item.
+ if ( isset( $this->raw_keys[0] ) ) {
+ $this->raw_keys[0] = $this->remove_utf8_bom( $this->raw_keys[0] );
+ }
+
+ if ( 0 !== $this->params['start_pos'] ) {
+ fseek( $handle, (int) $this->params['start_pos'] );
+ }
+
+ while ( 1 ) {
+ $row = version_compare( PHP_VERSION, '5.3', '>=' ) ? fgetcsv( $handle, 0, $this->params['delimiter'], $this->params['enclosure'], $this->params['escape'] ) : fgetcsv( $handle, 0, $this->params['delimiter'], $this->params['enclosure'] ); // @codingStandardsIgnoreLine
+
+ if ( false !== $row ) {
+ $this->raw_data[] = $row;
+ $this->file_positions[ count( $this->raw_data ) ] = ftell( $handle );
+
+ if ( ( $this->params['end_pos'] > 0 && ftell( $handle ) >= $this->params['end_pos'] ) || 0 === --$this->params['lines'] ) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ $this->file_position = ftell( $handle );
+ }
+
+ if ( ! empty( $this->params['mapping'] ) ) {
+ $this->set_mapped_keys();
+ }
+
+ if ( $this->params['parse'] ) {
+ $this->set_parsed_data();
+ }
+ }
+
+ /**
+ * Remove UTF-8 BOM signature.
+ *
+ * @param string $string String to handle.
+ *
+ * @return string
+ */
+ protected function remove_utf8_bom( $string ) {
+ if ( 'efbbbf' === substr( bin2hex( $string ), 0, 6 ) ) {
+ $string = substr( $string, 3 );
+ }
+
+ return $string;
+ }
+
+ /**
+ * Set file mapped keys.
+ */
+ protected function set_mapped_keys() {
+ $mapping = $this->params['mapping'];
+
+ foreach ( $this->raw_keys as $key ) {
+ $this->mapped_keys[] = isset( $mapping[ $key ] ) ? $mapping[ $key ] : $key;
+ }
+ }
+
+ /**
+ * Parse relative field and return product ID.
+ *
+ * Handles `id:xx` and SKUs.
+ *
+ * If mapping to an id: and the product ID does not exist, this link is not
+ * valid.
+ *
+ * If mapping to a SKU and the product ID does not exist, a temporary object
+ * will be created so it can be updated later.
+ *
+ * @param string $value Field value.
+ *
+ * @return int|string
+ */
+ public function parse_relative_field( $value ) {
+ global $wpdb;
+
+ if ( empty( $value ) ) {
+ return '';
+ }
+
+ // IDs are prefixed with id:.
+ if ( preg_match( '/^id:(\d+)$/', $value, $matches ) ) {
+ $id = intval( $matches[1] );
+
+ // If original_id is found, use that instead of the given ID since a new placeholder must have been created already.
+ $original_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = '_original_id' AND meta_value = %s;", $id ) ); // WPCS: db call ok, cache ok.
+
+ if ( $original_id ) {
+ return absint( $original_id );
+ }
+
+ // See if the given ID maps to a valid product allready.
+ $existing_id = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_type IN ( 'product', 'product_variation' ) AND ID = %d;", $id ) ); // WPCS: db call ok, cache ok.
+
+ if ( $existing_id ) {
+ return absint( $existing_id );
+ }
+
+ // If we're not updating existing posts, we may need a placeholder product to map to.
+ if ( ! $this->params['update_existing'] ) {
+ $product = wc_get_product_object( 'simple' );
+ $product->set_name( 'Import placeholder for ' . $id );
+ $product->set_status( 'importing' );
+ $product->add_meta_data( '_original_id', $id, true );
+ $id = $product->save();
+ }
+
+ return $id;
+ }
+
+ $id = wc_get_product_id_by_sku( $value );
+
+ if ( $id ) {
+ return $id;
+ }
+
+ try {
+ $product = wc_get_product_object( 'simple' );
+ $product->set_name( 'Import placeholder for ' . $value );
+ $product->set_status( 'importing' );
+ $product->set_sku( $value );
+ $id = $product->save();
+
+ if ( $id && ! is_wp_error( $id ) ) {
+ return $id;
+ }
+ } catch ( Exception $e ) {
+ return '';
+ }
+
+ return '';
+ }
+
+ /**
+ * Parse the ID field.
+ *
+ * If we're not doing an update, create a placeholder product so mapping works
+ * for rows following this one.
+ *
+ * @param string $value Field value.
+ *
+ * @return int
+ */
+ public function parse_id_field( $value ) {
+ global $wpdb;
+
+ $id = absint( $value );
+
+ if ( ! $id ) {
+ return 0;
+ }
+
+ // See if this maps to an ID placeholder already.
+ $original_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = '_original_id' AND meta_value = %s;", $id ) ); // WPCS: db call ok, cache ok.
+
+ if ( $original_id ) {
+ return absint( $original_id );
+ }
+
+ // Not updating? Make sure we have a new placeholder for this ID.
+ if ( ! $this->params['update_existing'] ) {
+ $mapped_keys = $this->get_mapped_keys();
+ $sku_column_index = absint( array_search( 'sku', $mapped_keys, true ) );
+ $row_sku = isset( $this->raw_data[ $this->parsing_raw_data_index ][ $sku_column_index ] ) ? $this->raw_data[ $this->parsing_raw_data_index ][ $sku_column_index ] : '';
+ $id_from_sku = $row_sku ? wc_get_product_id_by_sku( $row_sku ) : '';
+
+ // If row has a SKU, make sure placeholder was not made already.
+ if ( $id_from_sku ) {
+ return $id_from_sku;
+ }
+
+ $product = wc_get_product_object( 'simple' );
+ $product->set_name( 'Import placeholder for ' . $id );
+ $product->set_status( 'importing' );
+ $product->add_meta_data( '_original_id', $id, true );
+
+ // If row has a SKU, make sure placeholder has it too.
+ if ( $row_sku ) {
+ $product->set_sku( $row_sku );
+ }
+ $id = $product->save();
+ }
+
+ return $id && ! is_wp_error( $id ) ? $id : 0;
+ }
+
+ /**
+ * Parse relative comma-delineated field and return product ID.
+ *
+ * @param string $value Field value.
+ *
+ * @return array
+ */
+ public function parse_relative_comma_field( $value ) {
+ if ( empty( $value ) ) {
+ return array();
+ }
+
+ return array_filter( array_map( array( $this, 'parse_relative_field' ), $this->explode_values( $value ) ) );
+ }
+
+ /**
+ * Parse a comma-delineated field from a CSV.
+ *
+ * @param string $value Field value.
+ *
+ * @return array
+ */
+ public function parse_comma_field( $value ) {
+ if ( empty( $value ) && '0' !== $value ) {
+ return array();
+ }
+
+ $value = $this->unescape_data( $value );
+ return array_map( 'wc_clean', $this->explode_values( $value ) );
+ }
+
+ /**
+ * Parse a field that is generally '1' or '0' but can be something else.
+ *
+ * @param string $value Field value.
+ *
+ * @return bool|string
+ */
+ public function parse_bool_field( $value ) {
+ if ( '0' === $value ) {
+ return false;
+ }
+
+ if ( '1' === $value ) {
+ return true;
+ }
+
+ // Don't return explicit true or false for empty fields or values like 'notify'.
+ return wc_clean( $value );
+ }
+
+ /**
+ * Parse a float value field.
+ *
+ * @param string $value Field value.
+ *
+ * @return float|string
+ */
+ public function parse_float_field( $value ) {
+ if ( '' === $value ) {
+ return $value;
+ }
+
+ // Remove the ' prepended to fields that start with - if needed.
+ $value = $this->unescape_data( $value );
+
+ return floatval( $value );
+ }
+
+ /**
+ * Parse the stock qty field.
+ *
+ * @param string $value Field value.
+ *
+ * @return float|string
+ */
+ public function parse_stock_quantity_field( $value ) {
+ if ( '' === $value ) {
+ return $value;
+ }
+
+ // Remove the ' prepended to fields that start with - if needed.
+ $value = $this->unescape_data( $value );
+
+ return wc_stock_amount( $value );
+ }
+
+ /**
+ * Parse the tax status field.
+ *
+ * @param string $value Field value.
+ *
+ * @return string
+ */
+ public function parse_tax_status_field( $value ) {
+ if ( '' === $value ) {
+ return $value;
+ }
+
+ // Remove the ' prepended to fields that start with - if needed.
+ $value = $this->unescape_data( $value );
+
+ if ( 'true' === strtolower( $value ) || 'false' === strtolower( $value ) ) {
+ $value = wc_string_to_bool( $value ) ? 'taxable' : 'none';
+ }
+
+ return wc_clean( $value );
+ }
+
+ /**
+ * Parse a category field from a CSV.
+ * Categories are separated by commas and subcategories are "parent > subcategory".
+ *
+ * @param string $value Field value.
+ *
+ * @return array of arrays with "parent" and "name" keys.
+ */
+ public function parse_categories_field( $value ) {
+ if ( empty( $value ) ) {
+ return array();
+ }
+
+ $row_terms = $this->explode_values( $value );
+ $categories = array();
+
+ foreach ( $row_terms as $row_term ) {
+ $parent = null;
+ $_terms = array_map( 'trim', explode( '>', $row_term ) );
+ $total = count( $_terms );
+
+ foreach ( $_terms as $index => $_term ) {
+ // Don't allow users without capabilities to create new categories.
+ if ( ! current_user_can( 'manage_product_terms' ) ) {
+ break;
+ }
+
+ $term = wp_insert_term( $_term, 'product_cat', array( 'parent' => intval( $parent ) ) );
+
+ if ( is_wp_error( $term ) ) {
+ if ( $term->get_error_code() === 'term_exists' ) {
+ // When term exists, error data should contain existing term id.
+ $term_id = $term->get_error_data();
+ } else {
+ break; // We cannot continue on any other error.
+ }
+ } else {
+ // New term.
+ $term_id = $term['term_id'];
+ }
+
+ // Only requires assign the last category.
+ if ( ( 1 + $index ) === $total ) {
+ $categories[] = $term_id;
+ } else {
+ // Store parent to be able to insert or query categories based in parent ID.
+ $parent = $term_id;
+ }
+ }
+ }
+
+ return $categories;
+ }
+
+ /**
+ * Parse a tag field from a CSV.
+ *
+ * @param string $value Field value.
+ *
+ * @return array
+ */
+ public function parse_tags_field( $value ) {
+ if ( empty( $value ) ) {
+ return array();
+ }
+
+ $value = $this->unescape_data( $value );
+ $names = $this->explode_values( $value );
+ $tags = array();
+
+ foreach ( $names as $name ) {
+ $term = get_term_by( 'name', $name, 'product_tag' );
+
+ if ( ! $term || is_wp_error( $term ) ) {
+ $term = (object) wp_insert_term( $name, 'product_tag' );
+ }
+
+ if ( ! is_wp_error( $term ) ) {
+ $tags[] = $term->term_id;
+ }
+ }
+
+ return $tags;
+ }
+
+ /**
+ * Parse a tag field from a CSV with space separators.
+ *
+ * @param string $value Field value.
+ *
+ * @return array
+ */
+ public function parse_tags_spaces_field( $value ) {
+ if ( empty( $value ) ) {
+ return array();
+ }
+
+ $value = $this->unescape_data( $value );
+ $names = $this->explode_values( $value, ' ' );
+ $tags = array();
+
+ foreach ( $names as $name ) {
+ $term = get_term_by( 'name', $name, 'product_tag' );
+
+ if ( ! $term || is_wp_error( $term ) ) {
+ $term = (object) wp_insert_term( $name, 'product_tag' );
+ }
+
+ if ( ! is_wp_error( $term ) ) {
+ $tags[] = $term->term_id;
+ }
+ }
+
+ return $tags;
+ }
+
+ /**
+ * Parse a shipping class field from a CSV.
+ *
+ * @param string $value Field value.
+ *
+ * @return int
+ */
+ public function parse_shipping_class_field( $value ) {
+ if ( empty( $value ) ) {
+ return 0;
+ }
+
+ $term = get_term_by( 'name', $value, 'product_shipping_class' );
+
+ if ( ! $term || is_wp_error( $term ) ) {
+ $term = (object) wp_insert_term( $value, 'product_shipping_class' );
+ }
+
+ if ( is_wp_error( $term ) ) {
+ return 0;
+ }
+
+ return $term->term_id;
+ }
+
+ /**
+ * Parse images list from a CSV. Images can be filenames or URLs.
+ *
+ * @param string $value Field value.
+ *
+ * @return array
+ */
+ public function parse_images_field( $value ) {
+ if ( empty( $value ) ) {
+ return array();
+ }
+
+ $images = array();
+ $separator = apply_filters( 'woocommerce_product_import_image_separator', ',' );
+
+ foreach ( $this->explode_values( $value, $separator ) as $image ) {
+ if ( stristr( $image, '://' ) ) {
+ $images[] = esc_url_raw( $image );
+ } else {
+ $images[] = sanitize_file_name( $image );
+ }
+ }
+
+ return $images;
+ }
+
+ /**
+ * Parse dates from a CSV.
+ * Dates requires the format YYYY-MM-DD and time is optional.
+ *
+ * @param string $value Field value.
+ *
+ * @return string|null
+ */
+ public function parse_date_field( $value ) {
+ if ( empty( $value ) ) {
+ return null;
+ }
+
+ if ( preg_match( '/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])([ 01-9:]*)$/', $value ) ) {
+ // Don't include the time if the field had time in it.
+ return current( explode( ' ', $value ) );
+ }
+
+ return null;
+ }
+
+ /**
+ * Parse backorders from a CSV.
+ *
+ * @param string $value Field value.
+ *
+ * @return string
+ */
+ public function parse_backorders_field( $value ) {
+ if ( empty( $value ) ) {
+ return 'no';
+ }
+
+ $value = $this->parse_bool_field( $value );
+
+ if ( 'notify' === $value ) {
+ return 'notify';
+ } elseif ( is_bool( $value ) ) {
+ return $value ? 'yes' : 'no';
+ }
+
+ return 'no';
+ }
+
+ /**
+ * Just skip current field.
+ *
+ * By default is applied wc_clean() to all not listed fields
+ * in self::get_formatting_callback(), use this method to skip any formatting.
+ *
+ * @param string $value Field value.
+ *
+ * @return string
+ */
+ public function parse_skip_field( $value ) {
+ return $value;
+ }
+
+ /**
+ * Parse download file urls, we should allow shortcodes here.
+ *
+ * Allow shortcodes if present, othersiwe esc_url the value.
+ *
+ * @param string $value Field value.
+ *
+ * @return string
+ */
+ public function parse_download_file_field( $value ) {
+ // Absolute file paths.
+ if ( 0 === strpos( $value, 'http' ) ) {
+ return esc_url_raw( $value );
+ }
+ // Relative and shortcode paths.
+ return wc_clean( $value );
+ }
+
+ /**
+ * Parse an int value field
+ *
+ * @param int $value field value.
+ *
+ * @return int
+ */
+ public function parse_int_field( $value ) {
+ // Remove the ' prepended to fields that start with - if needed.
+ $value = $this->unescape_data( $value );
+
+ return intval( $value );
+ }
+
+ /**
+ * Parse a description value field
+ *
+ * @param string $description field value.
+ *
+ * @return string
+ */
+ public function parse_description_field( $description ) {
+ $parts = explode( "\\\\n", $description );
+ foreach ( $parts as $key => $part ) {
+ $parts[ $key ] = str_replace( '\n', "\n", $part );
+ }
+
+ return implode( '\\\n', $parts );
+ }
+
+ /**
+ * Parse the published field. 1 is published, 0 is private, -1 is draft.
+ * Alternatively, 'true' can be used for published and 'false' for draft.
+ *
+ * @param string $value Field value.
+ *
+ * @return float|string
+ */
+ public function parse_published_field( $value ) {
+ if ( '' === $value ) {
+ return $value;
+ }
+
+ // Remove the ' prepended to fields that start with - if needed.
+ $value = $this->unescape_data( $value );
+
+ if ( 'true' === strtolower( $value ) || 'false' === strtolower( $value ) ) {
+ return wc_string_to_bool( $value ) ? 1 : -1;
+ }
+
+ return floatval( $value );
+ }
+
+ /**
+ * Deprecated get formatting callback method.
+ *
+ * @deprecated 4.3.0
+ * @return array
+ */
+ protected function get_formating_callback() {
+ return $this->get_formatting_callback();
+ }
+
+ /**
+ * Get formatting callback.
+ *
+ * @since 4.3.0
+ * @return array
+ */
+ protected function get_formatting_callback() {
+
+ /**
+ * Columns not mentioned here will get parsed with 'wc_clean'.
+ * column_name => callback.
+ */
+ $data_formatting = array(
+ 'id' => array( $this, 'parse_id_field' ),
+ 'type' => array( $this, 'parse_comma_field' ),
+ 'published' => array( $this, 'parse_published_field' ),
+ 'featured' => array( $this, 'parse_bool_field' ),
+ 'date_on_sale_from' => array( $this, 'parse_date_field' ),
+ 'date_on_sale_to' => array( $this, 'parse_date_field' ),
+ 'name' => array( $this, 'parse_skip_field' ),
+ 'short_description' => array( $this, 'parse_description_field' ),
+ 'description' => array( $this, 'parse_description_field' ),
+ 'manage_stock' => array( $this, 'parse_bool_field' ),
+ 'low_stock_amount' => array( $this, 'parse_stock_quantity_field' ),
+ 'backorders' => array( $this, 'parse_backorders_field' ),
+ 'stock_status' => array( $this, 'parse_bool_field' ),
+ 'sold_individually' => array( $this, 'parse_bool_field' ),
+ 'width' => array( $this, 'parse_float_field' ),
+ 'length' => array( $this, 'parse_float_field' ),
+ 'height' => array( $this, 'parse_float_field' ),
+ 'weight' => array( $this, 'parse_float_field' ),
+ 'reviews_allowed' => array( $this, 'parse_bool_field' ),
+ 'purchase_note' => 'wp_filter_post_kses',
+ 'price' => 'wc_format_decimal',
+ 'regular_price' => 'wc_format_decimal',
+ 'stock_quantity' => array( $this, 'parse_stock_quantity_field' ),
+ 'category_ids' => array( $this, 'parse_categories_field' ),
+ 'tag_ids' => array( $this, 'parse_tags_field' ),
+ 'tag_ids_spaces' => array( $this, 'parse_tags_spaces_field' ),
+ 'shipping_class_id' => array( $this, 'parse_shipping_class_field' ),
+ 'images' => array( $this, 'parse_images_field' ),
+ 'parent_id' => array( $this, 'parse_relative_field' ),
+ 'grouped_products' => array( $this, 'parse_relative_comma_field' ),
+ 'upsell_ids' => array( $this, 'parse_relative_comma_field' ),
+ 'cross_sell_ids' => array( $this, 'parse_relative_comma_field' ),
+ 'download_limit' => array( $this, 'parse_int_field' ),
+ 'download_expiry' => array( $this, 'parse_int_field' ),
+ 'product_url' => 'esc_url_raw',
+ 'menu_order' => 'intval',
+ 'tax_status' => array( $this, 'parse_tax_status_field' ),
+ );
+
+ /**
+ * Match special column names.
+ */
+ $regex_match_data_formatting = array(
+ '/attributes:value*/' => array( $this, 'parse_comma_field' ),
+ '/attributes:visible*/' => array( $this, 'parse_bool_field' ),
+ '/attributes:taxonomy*/' => array( $this, 'parse_bool_field' ),
+ '/downloads:url*/' => array( $this, 'parse_download_file_field' ),
+ '/meta:*/' => 'wp_kses_post', // Allow some HTML in meta fields.
+ );
+
+ $callbacks = array();
+
+ // Figure out the parse function for each column.
+ foreach ( $this->get_mapped_keys() as $index => $heading ) {
+ $callback = 'wc_clean';
+
+ if ( isset( $data_formatting[ $heading ] ) ) {
+ $callback = $data_formatting[ $heading ];
+ } else {
+ foreach ( $regex_match_data_formatting as $regex => $callback ) {
+ if ( preg_match( $regex, $heading ) ) {
+ $callback = $callback;
+ break;
+ }
+ }
+ }
+
+ $callbacks[] = $callback;
+ }
+
+ return apply_filters( 'woocommerce_product_importer_formatting_callbacks', $callbacks, $this );
+ }
+
+ /**
+ * Check if strings starts with determined word.
+ *
+ * @param string $haystack Complete sentence.
+ * @param string $needle Excerpt.
+ *
+ * @return bool
+ */
+ protected function starts_with( $haystack, $needle ) {
+ return substr( $haystack, 0, strlen( $needle ) ) === $needle;
+ }
+
+ /**
+ * Expand special and internal data into the correct formats for the product CRUD.
+ *
+ * @param array $data Data to import.
+ *
+ * @return array
+ */
+ protected function expand_data( $data ) {
+ $data = apply_filters( 'woocommerce_product_importer_pre_expand_data', $data );
+
+ // Images field maps to image and gallery id fields.
+ if ( isset( $data['images'] ) ) {
+ $images = $data['images'];
+ $data['raw_image_id'] = array_shift( $images );
+
+ if ( ! empty( $images ) ) {
+ $data['raw_gallery_image_ids'] = $images;
+ }
+ unset( $data['images'] );
+ }
+
+ // Type, virtual and downloadable are all stored in the same column.
+ if ( isset( $data['type'] ) ) {
+ $data['type'] = array_map( 'strtolower', $data['type'] );
+ $data['virtual'] = in_array( 'virtual', $data['type'], true );
+ $data['downloadable'] = in_array( 'downloadable', $data['type'], true );
+
+ // Convert type to string.
+ $data['type'] = current( array_diff( $data['type'], array( 'virtual', 'downloadable' ) ) );
+
+ if ( ! $data['type'] ) {
+ $data['type'] = 'simple';
+ }
+ }
+
+ // Status is mapped from a special published field.
+ if ( isset( $data['published'] ) ) {
+ $statuses = array(
+ -1 => 'draft',
+ 0 => 'private',
+ 1 => 'publish',
+ );
+ $data['status'] = isset( $statuses[ $data['published'] ] ) ? $statuses[ $data['published'] ] : 'draft';
+
+ // Fix draft status of variations.
+ if ( isset( $data['type'] ) && 'variation' === $data['type'] && -1 === $data['published'] ) {
+ $data['status'] = 'publish';
+ }
+
+ unset( $data['published'] );
+ }
+
+ if ( isset( $data['stock_quantity'] ) ) {
+ if ( '' === $data['stock_quantity'] ) {
+ $data['manage_stock'] = false;
+ $data['stock_status'] = isset( $data['stock_status'] ) ? $data['stock_status'] : true;
+ } else {
+ $data['manage_stock'] = true;
+ }
+ }
+
+ // Stock is bool or 'backorder'.
+ if ( isset( $data['stock_status'] ) ) {
+ if ( 'backorder' === $data['stock_status'] ) {
+ $data['stock_status'] = 'onbackorder';
+ } else {
+ $data['stock_status'] = $data['stock_status'] ? 'instock' : 'outofstock';
+ }
+ }
+
+ // Prepare grouped products.
+ if ( isset( $data['grouped_products'] ) ) {
+ $data['children'] = $data['grouped_products'];
+ unset( $data['grouped_products'] );
+ }
+
+ // Tag ids.
+ if ( isset( $data['tag_ids_spaces'] ) ) {
+ $data['tag_ids'] = $data['tag_ids_spaces'];
+ unset( $data['tag_ids_spaces'] );
+ }
+
+ // Handle special column names which span multiple columns.
+ $attributes = array();
+ $downloads = array();
+ $meta_data = array();
+
+ foreach ( $data as $key => $value ) {
+ if ( $this->starts_with( $key, 'attributes:name' ) ) {
+ if ( ! empty( $value ) ) {
+ $attributes[ str_replace( 'attributes:name', '', $key ) ]['name'] = $value;
+ }
+ unset( $data[ $key ] );
+
+ } elseif ( $this->starts_with( $key, 'attributes:value' ) ) {
+ $attributes[ str_replace( 'attributes:value', '', $key ) ]['value'] = $value;
+ unset( $data[ $key ] );
+
+ } elseif ( $this->starts_with( $key, 'attributes:taxonomy' ) ) {
+ $attributes[ str_replace( 'attributes:taxonomy', '', $key ) ]['taxonomy'] = wc_string_to_bool( $value );
+ unset( $data[ $key ] );
+
+ } elseif ( $this->starts_with( $key, 'attributes:visible' ) ) {
+ $attributes[ str_replace( 'attributes:visible', '', $key ) ]['visible'] = wc_string_to_bool( $value );
+ unset( $data[ $key ] );
+
+ } elseif ( $this->starts_with( $key, 'attributes:default' ) ) {
+ if ( ! empty( $value ) ) {
+ $attributes[ str_replace( 'attributes:default', '', $key ) ]['default'] = $value;
+ }
+ unset( $data[ $key ] );
+
+ } elseif ( $this->starts_with( $key, 'downloads:name' ) ) {
+ if ( ! empty( $value ) ) {
+ $downloads[ str_replace( 'downloads:name', '', $key ) ]['name'] = $value;
+ }
+ unset( $data[ $key ] );
+
+ } elseif ( $this->starts_with( $key, 'downloads:url' ) ) {
+ if ( ! empty( $value ) ) {
+ $downloads[ str_replace( 'downloads:url', '', $key ) ]['url'] = $value;
+ }
+ unset( $data[ $key ] );
+
+ } elseif ( $this->starts_with( $key, 'meta:' ) ) {
+ $meta_data[] = array(
+ 'key' => str_replace( 'meta:', '', $key ),
+ 'value' => $value,
+ );
+ unset( $data[ $key ] );
+ }
+ }
+
+ if ( ! empty( $attributes ) ) {
+ // Remove empty attributes and clear indexes.
+ foreach ( $attributes as $attribute ) {
+ if ( empty( $attribute['name'] ) ) {
+ continue;
+ }
+
+ $data['raw_attributes'][] = $attribute;
+ }
+ }
+
+ if ( ! empty( $downloads ) ) {
+ $data['downloads'] = array();
+
+ foreach ( $downloads as $key => $file ) {
+ if ( empty( $file['url'] ) ) {
+ continue;
+ }
+
+ $data['downloads'][] = array(
+ 'name' => $file['name'] ? $file['name'] : wc_get_filename_from_url( $file['url'] ),
+ 'file' => $file['url'],
+ );
+ }
+ }
+
+ if ( ! empty( $meta_data ) ) {
+ $data['meta_data'] = $meta_data;
+ }
+
+ return $data;
+ }
+
+ /**
+ * Map and format raw data to known fields.
+ */
+ protected function set_parsed_data() {
+ $parse_functions = $this->get_formatting_callback();
+ $mapped_keys = $this->get_mapped_keys();
+ $use_mb = function_exists( 'mb_convert_encoding' );
+
+ // Parse the data.
+ foreach ( $this->raw_data as $row_index => $row ) {
+ // Skip empty rows.
+ if ( ! count( array_filter( $row ) ) ) {
+ continue;
+ }
+
+ $this->parsing_raw_data_index = $row_index;
+
+ $data = array();
+
+ do_action( 'woocommerce_product_importer_before_set_parsed_data', $row, $mapped_keys );
+
+ foreach ( $row as $id => $value ) {
+ // Skip ignored columns.
+ if ( empty( $mapped_keys[ $id ] ) ) {
+ continue;
+ }
+
+ // Convert UTF8.
+ if ( $use_mb ) {
+ $encoding = mb_detect_encoding( $value, mb_detect_order(), true );
+ if ( $encoding ) {
+ $value = mb_convert_encoding( $value, 'UTF-8', $encoding );
+ } else {
+ $value = mb_convert_encoding( $value, 'UTF-8', 'UTF-8' );
+ }
+ } else {
+ $value = wp_check_invalid_utf8( $value, true );
+ }
+
+ $data[ $mapped_keys[ $id ] ] = call_user_func( $parse_functions[ $id ], $value );
+ }
+
+ /**
+ * Filter product importer parsed data.
+ *
+ * @param array $parsed_data Parsed data.
+ * @param WC_Product_Importer $importer Importer instance.
+ */
+ $this->parsed_data[] = apply_filters( 'woocommerce_product_importer_parsed_data', $this->expand_data( $data ), $this );
+ }
+ }
+
+ /**
+ * Get a string to identify the row from parsed data.
+ *
+ * @param array $parsed_data Parsed data.
+ *
+ * @return string
+ */
+ protected function get_row_id( $parsed_data ) {
+ $id = isset( $parsed_data['id'] ) ? absint( $parsed_data['id'] ) : 0;
+ $sku = isset( $parsed_data['sku'] ) ? esc_attr( $parsed_data['sku'] ) : '';
+ $name = isset( $parsed_data['name'] ) ? esc_attr( $parsed_data['name'] ) : '';
+ $row_data = array();
+
+ if ( $name ) {
+ $row_data[] = $name;
+ }
+ if ( $id ) {
+ /* translators: %d: product ID */
+ $row_data[] = sprintf( __( 'ID %d', 'woocommerce' ), $id );
+ }
+ if ( $sku ) {
+ /* translators: %s: product SKU */
+ $row_data[] = sprintf( __( 'SKU %s', 'woocommerce' ), $sku );
+ }
+
+ return implode( ', ', $row_data );
+ }
+
+ /**
+ * Process importer.
+ *
+ * Do not import products with IDs or SKUs that already exist if option
+ * update existing is false, and likewise, if updating products, do not
+ * process rows which do not exist if an ID/SKU is provided.
+ *
+ * @return array
+ */
+ public function import() {
+ $this->start_time = time();
+ $index = 0;
+ $update_existing = $this->params['update_existing'];
+ $data = array(
+ 'imported' => array(),
+ 'failed' => array(),
+ 'updated' => array(),
+ 'skipped' => array(),
+ );
+
+ foreach ( $this->parsed_data as $parsed_data_key => $parsed_data ) {
+ do_action( 'woocommerce_product_import_before_import', $parsed_data );
+
+ $id = isset( $parsed_data['id'] ) ? absint( $parsed_data['id'] ) : 0;
+ $sku = isset( $parsed_data['sku'] ) ? $parsed_data['sku'] : '';
+ $id_exists = false;
+ $sku_exists = false;
+
+ if ( $id ) {
+ $product = wc_get_product( $id );
+ $id_exists = $product && 'importing' !== $product->get_status();
+ }
+
+ if ( $sku ) {
+ $id_from_sku = wc_get_product_id_by_sku( $sku );
+ $product = $id_from_sku ? wc_get_product( $id_from_sku ) : false;
+ $sku_exists = $product && 'importing' !== $product->get_status();
+ }
+
+ if ( $id_exists && ! $update_existing ) {
+ $data['skipped'][] = new WP_Error(
+ 'woocommerce_product_importer_error',
+ esc_html__( 'A product with this ID already exists.', 'woocommerce' ),
+ array(
+ 'id' => $id,
+ 'row' => $this->get_row_id( $parsed_data ),
+ )
+ );
+ continue;
+ }
+
+ if ( $sku_exists && ! $update_existing ) {
+ $data['skipped'][] = new WP_Error(
+ 'woocommerce_product_importer_error',
+ esc_html__( 'A product with this SKU already exists.', 'woocommerce' ),
+ array(
+ 'sku' => esc_attr( $sku ),
+ 'row' => $this->get_row_id( $parsed_data ),
+ )
+ );
+ continue;
+ }
+
+ if ( $update_existing && ( isset( $parsed_data['id'] ) || isset( $parsed_data['sku'] ) ) && ! $id_exists && ! $sku_exists ) {
+ $data['skipped'][] = new WP_Error(
+ 'woocommerce_product_importer_error',
+ esc_html__( 'No matching product exists to update.', 'woocommerce' ),
+ array(
+ 'id' => $id,
+ 'sku' => esc_attr( $sku ),
+ 'row' => $this->get_row_id( $parsed_data ),
+ )
+ );
+ continue;
+ }
+
+ $result = $this->process_item( $parsed_data );
+
+ if ( is_wp_error( $result ) ) {
+ $result->add_data( array( 'row' => $this->get_row_id( $parsed_data ) ) );
+ $data['failed'][] = $result;
+ } elseif ( $result['updated'] ) {
+ $data['updated'][] = $result['id'];
+ } else {
+ $data['imported'][] = $result['id'];
+ }
+
+ $index ++;
+
+ if ( $this->params['prevent_timeouts'] && ( $this->time_exceeded() || $this->memory_exceeded() ) ) {
+ $this->file_position = $this->file_positions[ $index ];
+ break;
+ }
+ }
+
+ return $data;
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/integrations/maxmind-geolocation/class-wc-integration-maxmind-database-service.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/integrations/maxmind-geolocation/class-wc-integration-maxmind-database-service.php
new file mode 100644
index 0000000..8a78efb
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/integrations/maxmind-geolocation/class-wc-integration-maxmind-database-service.php
@@ -0,0 +1,172 @@
+database_prefix = $database_prefix;
+ }
+
+ /**
+ * Fetches the path that the database should be stored.
+ *
+ * @return string The local database path.
+ */
+ public function get_database_path() {
+ $uploads_dir = wp_upload_dir();
+
+ $database_path = trailingslashit( $uploads_dir['basedir'] ) . 'woocommerce_uploads/';
+ if ( ! empty( $this->database_prefix ) ) {
+ $database_path .= $this->database_prefix . '-';
+ }
+ $database_path .= self::DATABASE . self::DATABASE_EXTENSION;
+
+ /**
+ * Filter the geolocation database storage path.
+ *
+ * @param string $database_path The path to the database.
+ * @param int $version Deprecated since 3.4.0.
+ * @deprecated 3.9.0
+ */
+ $database_path = apply_filters_deprecated(
+ 'woocommerce_geolocation_local_database_path',
+ array( $database_path, 2 ),
+ '3.9.0',
+ 'woocommerce_maxmind_geolocation_database_path'
+ );
+
+ /**
+ * Filter the geolocation database storage path.
+ *
+ * @since 3.9.0
+ * @param string $database_path The path to the database.
+ */
+ return apply_filters( 'woocommerce_maxmind_geolocation_database_path', $database_path );
+ }
+
+ /**
+ * Fetches the database from the MaxMind service.
+ *
+ * @param string $license_key The license key to be used when downloading the database.
+ * @return string|WP_Error The path to the database file or an error if invalid.
+ */
+ public function download_database( $license_key ) {
+ $download_uri = add_query_arg(
+ array(
+ 'edition_id' => self::DATABASE,
+ 'license_key' => urlencode( wc_clean( $license_key ) ),
+ 'suffix' => 'tar.gz',
+ ),
+ 'https://download.maxmind.com/app/geoip_download'
+ );
+
+ // Needed for the download_url call right below.
+ require_once ABSPATH . 'wp-admin/includes/file.php';
+
+ $tmp_archive_path = download_url( esc_url_raw( $download_uri ) );
+ if ( is_wp_error( $tmp_archive_path ) ) {
+ // Transform the error into something more informative.
+ $error_data = $tmp_archive_path->get_error_data();
+ if ( isset( $error_data['code'] ) ) {
+ switch ( $error_data['code'] ) {
+ case 401:
+ return new WP_Error(
+ 'woocommerce_maxmind_geolocation_database_license_key',
+ __( 'The MaxMind license key is invalid. If you have recently created this key, you may need to wait for it to become active.', 'woocommerce' )
+ );
+ }
+ }
+
+ return new WP_Error( 'woocommerce_maxmind_geolocation_database_download', __( 'Failed to download the MaxMind database.', 'woocommerce' ) );
+ }
+
+ // Extract the database from the archive.
+ try {
+ $file = new PharData( $tmp_archive_path );
+
+ $tmp_database_path = trailingslashit( dirname( $tmp_archive_path ) ) . trailingslashit( $file->current()->getFilename() ) . self::DATABASE . self::DATABASE_EXTENSION;
+
+ $file->extractTo(
+ dirname( $tmp_archive_path ),
+ trailingslashit( $file->current()->getFilename() ) . self::DATABASE . self::DATABASE_EXTENSION,
+ true
+ );
+ } catch ( Exception $exception ) {
+ return new WP_Error( 'woocommerce_maxmind_geolocation_database_archive', $exception->getMessage() );
+ } finally {
+ // Remove the archive since we only care about a single file in it.
+ unlink( $tmp_archive_path );
+ }
+
+ return $tmp_database_path;
+ }
+
+ /**
+ * Fetches the ISO country code associated with an IP address.
+ *
+ * @param string $ip_address The IP address to find the country code for.
+ * @return string The country code for the IP address, or empty if not found.
+ */
+ public function get_iso_country_code_for_ip( $ip_address ) {
+ $country_code = '';
+
+ if ( ! class_exists( 'MaxMind\Db\Reader' ) ) {
+ wc_get_logger()->notice( __( 'Missing MaxMind Reader library!', 'woocommerce' ), array( 'source' => 'maxmind-geolocation' ) );
+ return $country_code;
+ }
+
+ $database_path = $this->get_database_path();
+ if ( ! file_exists( $database_path ) ) {
+ return $country_code;
+ }
+
+ try {
+ $reader = new MaxMind\Db\Reader( $database_path );
+ $data = $reader->get( $ip_address );
+
+ if ( isset( $data['country']['iso_code'] ) ) {
+ $country_code = $data['country']['iso_code'];
+ }
+
+ $reader->close();
+ } catch ( Exception $e ) {
+ wc_get_logger()->notice( $e->getMessage(), array( 'source' => 'maxmind-geolocation' ) );
+ }
+
+ return $country_code;
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/integrations/maxmind-geolocation/class-wc-integration-maxmind-geolocation.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/integrations/maxmind-geolocation/class-wc-integration-maxmind-geolocation.php
new file mode 100644
index 0000000..43c3c26
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/integrations/maxmind-geolocation/class-wc-integration-maxmind-geolocation.php
@@ -0,0 +1,292 @@
+id = 'maxmind_geolocation';
+ $this->method_title = __( 'MaxMind Geolocation', 'woocommerce' );
+ $this->method_description = __( 'An integration for utilizing MaxMind to do Geolocation lookups. Please note that this integration will only do country lookups.', 'woocommerce' );
+
+ /**
+ * Supports overriding the database service to be used.
+ *
+ * @since 3.9.0
+ * @return mixed|null The geolocation database service.
+ */
+ $this->database_service = apply_filters( 'woocommerce_maxmind_geolocation_database_service', null );
+ if ( null === $this->database_service ) {
+ $this->database_service = new WC_Integration_MaxMind_Database_Service( $this->get_database_prefix() );
+ }
+
+ $this->init_form_fields();
+ $this->init_settings();
+
+ // Bind to the save action for the settings.
+ add_action( 'woocommerce_update_options_integration_' . $this->id, array( $this, 'process_admin_options' ) );
+
+ // Trigger notice if license key is missing.
+ add_action( 'update_option_woocommerce_default_customer_address', array( $this, 'display_missing_license_key_notice' ), 1000, 2 );
+
+ /**
+ * Allows for the automatic database update to be disabled.
+ *
+ * @deprecated 3.9.0
+ * @return bool Whether or not the database should be updated periodically.
+ */
+ $bind_updater = apply_filters_deprecated(
+ 'woocommerce_geolocation_update_database_periodically',
+ array( true ),
+ '3.9.0',
+ 'woocommerce_maxmind_geolocation_update_database_periodically'
+ );
+
+ /**
+ * Allows for the automatic database update to be disabled.
+ * Note that MaxMind's TOS requires that the databases be updated or removed periodically.
+ *
+ * @since 3.9.0
+ * @param bool $bind_updater Whether or not the database should be updated periodically.
+ */
+ $bind_updater = apply_filters( 'woocommerce_maxmind_geolocation_update_database_periodically', $bind_updater );
+
+ // Bind to the scheduled updater action.
+ if ( $bind_updater ) {
+ add_action( 'woocommerce_geoip_updater', array( $this, 'update_database' ) );
+ }
+
+ // Bind to the geolocation filter for MaxMind database lookups.
+ add_filter( 'woocommerce_get_geolocation', array( $this, 'get_geolocation' ), 10, 2 );
+ }
+
+ /**
+ * Override the normal options so we can print the database file path to the admin,
+ */
+ public function admin_options() {
+ parent::admin_options();
+
+ include dirname( __FILE__ ) . '/views/html-admin-options.php';
+ }
+
+ /**
+ * Initializes the settings fields.
+ */
+ public function init_form_fields() {
+ $this->form_fields = array(
+ 'license_key' => array(
+ 'title' => __( 'MaxMind License Key', 'woocommerce' ),
+ 'type' => 'password',
+ 'description' => sprintf(
+ /* translators: %1$s: Documentation URL */
+ __(
+ 'The key that will be used when dealing with MaxMind Geolocation services. You can read how to generate one in MaxMind Geolocation Integration documentation.',
+ 'woocommerce'
+ ),
+ 'https://docs.woocommerce.com/document/maxmind-geolocation-integration/'
+ ),
+ 'desc_tip' => false,
+ 'default' => '',
+ ),
+ );
+ }
+
+ /**
+ * Get database service.
+ *
+ * @return WC_Integration_MaxMind_Database_Service|null
+ */
+ public function get_database_service() {
+ return $this->database_service;
+ }
+
+ /**
+ * Checks to make sure that the license key is valid.
+ *
+ * @param string $key The key of the field.
+ * @param mixed $value The value of the field.
+ * @return mixed
+ * @throws Exception When the license key is invalid.
+ */
+ public function validate_license_key_field( $key, $value ) {
+ // Trim whitespaces and strip slashes.
+ $value = $this->validate_password_field( $key, $value );
+
+ // Empty license keys have no need test downloading a database.
+ if ( empty( $value ) ) {
+ return $value;
+ }
+
+ // Check the license key by attempting to download the Geolocation database.
+ $tmp_database_path = $this->database_service->download_database( $value );
+ if ( is_wp_error( $tmp_database_path ) ) {
+ WC_Admin_Settings::add_error( $tmp_database_path->get_error_message() );
+
+ // Throw an exception to keep from changing this value. This will prevent
+ // users from accidentally losing their license key, which cannot
+ // be viewed again after generating.
+ throw new Exception( $tmp_database_path->get_error_message() );
+ }
+
+ // We may as well put this archive to good use, now that we've downloaded one.
+ self::update_database( $tmp_database_path );
+
+ // Remove missing license key notice.
+ $this->remove_missing_license_key_notice();
+
+ return $value;
+ }
+
+ /**
+ * Updates the database used for geolocation queries.
+ *
+ * @param string|null $new_database_path The path to the new database file. Null will fetch a new archive.
+ */
+ public function update_database( $new_database_path = null ) {
+ // Allow us to easily interact with the filesystem.
+ require_once ABSPATH . 'wp-admin/includes/file.php';
+ WP_Filesystem();
+ global $wp_filesystem;
+
+ // Remove any existing archives to comply with the MaxMind TOS.
+ $target_database_path = $this->database_service->get_database_path();
+
+ // If there's no database path, we can't store the database.
+ if ( empty( $target_database_path ) ) {
+ return;
+ }
+
+ if ( $wp_filesystem->exists( $target_database_path ) ) {
+ $wp_filesystem->delete( $target_database_path );
+ }
+
+ if ( isset( $new_database_path ) ) {
+ $tmp_database_path = $new_database_path;
+ } else {
+ // We can't download a database if there's no license key configured.
+ $license_key = $this->get_option( 'license_key' );
+ if ( empty( $license_key ) ) {
+ return;
+ }
+
+ $tmp_database_path = $this->database_service->download_database( $license_key );
+ if ( is_wp_error( $tmp_database_path ) ) {
+ wc_get_logger()->notice( $tmp_database_path->get_error_message(), array( 'source' => 'maxmind-geolocation' ) );
+ return;
+ }
+ }
+
+ // Move the new database into position.
+ $wp_filesystem->move( $tmp_database_path, $target_database_path, true );
+ $wp_filesystem->delete( dirname( $tmp_database_path ) );
+ }
+
+ /**
+ * Performs a geolocation lookup against the MaxMind database for the given IP address.
+ *
+ * @param array $data Geolocation data.
+ * @param string $ip_address The IP address to geolocate.
+ * @return array Geolocation including country code, state, city and postcode based on an IP address.
+ */
+ public function get_geolocation( $data, $ip_address ) {
+ // WooCommerce look for headers first, and at this moment could be just enough.
+ if ( ! empty( $data['country'] ) ) {
+ return $data;
+ }
+
+ if ( empty( $ip_address ) ) {
+ return $data;
+ }
+
+ $country_code = $this->database_service->get_iso_country_code_for_ip( $ip_address );
+
+ return array(
+ 'country' => $country_code,
+ 'state' => '',
+ 'city' => '',
+ 'postcode' => '',
+ );
+ }
+
+ /**
+ * Fetches the prefix for the MaxMind database file.
+ *
+ * @return string
+ */
+ private function get_database_prefix() {
+ $prefix = $this->get_option( 'database_prefix' );
+ if ( empty( $prefix ) ) {
+ $prefix = wp_generate_password( 32, false );
+ $this->update_option( 'database_prefix', $prefix );
+ }
+
+ return $prefix;
+ }
+
+ /**
+ * Add missing license key notice.
+ */
+ private function add_missing_license_key_notice() {
+ if ( ! class_exists( 'WC_Admin_Notices' ) ) {
+ include_once WC_ABSPATH . 'includes/admin/class-wc-admin-notices.php';
+ }
+ WC_Admin_Notices::add_notice( 'maxmind_license_key' );
+ }
+
+ /**
+ * Remove missing license key notice.
+ */
+ private function remove_missing_license_key_notice() {
+ if ( ! class_exists( 'WC_Admin_Notices' ) ) {
+ include_once WC_ABSPATH . 'includes/admin/class-wc-admin-notices.php';
+ }
+ WC_Admin_Notices::remove_notice( 'maxmind_license_key' );
+ }
+
+ /**
+ * Display notice if license key is missing.
+ *
+ * @param mixed $old_value Option old value.
+ * @param mixed $new_value Current value.
+ */
+ public function display_missing_license_key_notice( $old_value, $new_value ) {
+ if ( ! apply_filters( 'woocommerce_maxmind_geolocation_display_notices', true ) ) {
+ return;
+ }
+
+ if ( ! in_array( $new_value, array( 'geolocation', 'geolocation_ajax' ), true ) ) {
+ $this->remove_missing_license_key_notice();
+ return;
+ }
+
+ $license_key = $this->get_option( 'license_key' );
+ if ( ! empty( $license_key ) ) {
+ return;
+ }
+
+ $this->add_missing_license_key_notice();
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/integrations/maxmind-geolocation/views/html-admin-options.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/integrations/maxmind-geolocation/views/html-admin-options.php
new file mode 100644
index 0000000..a027e00
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/integrations/maxmind-geolocation/views/html-admin-options.php
@@ -0,0 +1,25 @@
+
+
+
+
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/interfaces/class-wc-abstract-order-data-store-interface.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/interfaces/class-wc-abstract-order-data-store-interface.php
new file mode 100644
index 0000000..c043c34
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/interfaces/class-wc-abstract-order-data-store-interface.php
@@ -0,0 +1,54 @@
+ [], 'failed' => []]
+ *
+ * @return array
+ */
+ public function import();
+
+ /**
+ * Get file raw keys.
+ *
+ * CSV - Headers.
+ * XML - Element names.
+ * JSON - Keys
+ *
+ * @return array
+ */
+ public function get_raw_keys();
+
+ /**
+ * Get file mapped headers.
+ *
+ * @return array
+ */
+ public function get_mapped_keys();
+
+ /**
+ * Get raw data.
+ *
+ * @return array
+ */
+ public function get_raw_data();
+
+ /**
+ * Get parsed data.
+ *
+ * @return array
+ */
+ public function get_parsed_data();
+
+ /**
+ * Get file pointer position from the last read.
+ *
+ * @return int
+ */
+ public function get_file_position();
+
+ /**
+ * Get file pointer position as a percentage of file size.
+ *
+ * @return int
+ */
+ public function get_percent_complete();
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/interfaces/class-wc-log-handler-interface.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/interfaces/class-wc-log-handler-interface.php
new file mode 100644
index 0000000..d84e397
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/interfaces/class-wc-log-handler-interface.php
@@ -0,0 +1,33 @@
+id).
+ * @return array
+ */
+ public function delete_meta( &$data, $meta );
+
+ /**
+ * Add new piece of meta.
+ *
+ * @param WC_Data $data Data object.
+ * @param object $meta Meta object (containing ->key and ->value).
+ * @return int meta ID
+ */
+ public function add_meta( &$data, $meta );
+
+ /**
+ * Update meta.
+ *
+ * @param WC_Data $data Data object.
+ * @param object $meta Meta object (containing ->id, ->key and ->value).
+ */
+ public function update_meta( &$data, $meta );
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/interfaces/class-wc-order-data-store-interface.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/interfaces/class-wc-order-data-store-interface.php
new file mode 100644
index 0000000..6f00c8a
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/interfaces/class-wc-order-data-store-interface.php
@@ -0,0 +1,141 @@
+get_id() will be set.
+ *
+ * @param WC_Order_Item $item Item object.
+ */
+ public function save_item_data( &$item );
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/interfaces/class-wc-order-refund-data-store-interface.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/interfaces/class-wc-order-refund-data-store-interface.php
new file mode 100644
index 0000000..b97864d
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/interfaces/class-wc-order-refund-data-store-interface.php
@@ -0,0 +1,21 @@
+id, $return[0]->parent_id.
+ *
+ * @return array
+ */
+ public function get_on_sale_products();
+
+ /**
+ * Returns a list of product IDs ( id as key => parent as value) that are
+ * featured. Uses get_posts instead of wc_get_products since we want
+ * some extra meta queries and ALL products (posts_per_page = -1).
+ *
+ * @return array
+ */
+ public function get_featured_product_ids();
+
+ /**
+ * Check if product sku is found for any other product IDs.
+ *
+ * @param int $product_id Product ID.
+ * @param string $sku SKU.
+ * @return bool
+ */
+ public function is_existing_sku( $product_id, $sku );
+
+ /**
+ * Return product ID based on SKU.
+ *
+ * @param string $sku SKU.
+ * @return int
+ */
+ public function get_product_id_by_sku( $sku );
+
+ /**
+ * Returns an array of IDs of products that have sales starting soon.
+ *
+ * @return array
+ */
+ public function get_starting_sales();
+
+ /**
+ * Returns an array of IDs of products that have sales which are due to end.
+ *
+ * @return array
+ */
+ public function get_ending_sales();
+
+ /**
+ * Find a matching (enabled) variation within a variable product.
+ *
+ * @param WC_Product $product Variable product object.
+ * @param array $match_attributes Array of attributes we want to try to match.
+ * @return int Matching variation ID or 0.
+ */
+ public function find_matching_product_variation( $product, $match_attributes = array() );
+
+ /**
+ * Make sure all variations have a sort order set so they can be reordered correctly.
+ *
+ * @param int $parent_id Parent ID.
+ */
+ public function sort_all_product_variations( $parent_id );
+
+ /**
+ * Return a list of related products (using data like categories and IDs).
+ *
+ * @param array $cats_array List of categories IDs.
+ * @param array $tags_array List of tags IDs.
+ * @param array $exclude_ids Excluded IDs.
+ * @param int $limit Limit of results.
+ * @param int $product_id Product ID.
+ * @return array
+ */
+ public function get_related_products( $cats_array, $tags_array, $exclude_ids, $limit, $product_id );
+
+ /**
+ * Update a product's stock amount directly.
+ *
+ * Uses queries rather than update_post_meta so we can do this in one query (to avoid stock issues).
+ *
+ * @param int $product_id_with_stock Product ID.
+ * @param int|null $stock_quantity Stock quantity to update to.
+ * @param string $operation Either set, increase or decrease.
+ */
+ public function update_product_stock( $product_id_with_stock, $stock_quantity = null, $operation = 'set' );
+
+ /**
+ * Update a product's sale count directly.
+ *
+ * Uses queries rather than update_post_meta so we can do this in one query for performance.
+ *
+ * @param int $product_id Product ID.
+ * @param int|null $quantity Stock quantity to use for update.
+ * @param string $operation Either set, increase or decrease.
+ */
+ public function update_product_sales( $product_id, $quantity = null, $operation = 'set' );
+
+ /**
+ * Get shipping class ID by slug.
+ *
+ * @param string $slug Shipping class slug.
+ * @return int|false
+ */
+ public function get_shipping_class_id_by_slug( $slug );
+
+ /**
+ * Returns an array of products.
+ *
+ * @param array $args @see wc_get_products.
+ * @return array
+ */
+ public function get_products( $args = array() );
+
+ /**
+ * Get the product type based on product ID.
+ *
+ * @param int $product_id Product ID.
+ * @return bool|string
+ */
+ public function get_product_type( $product_id );
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/interfaces/class-wc-product-variable-data-store-interface.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/interfaces/class-wc-product-variable-data-store-interface.php
new file mode 100644
index 0000000..b22893d
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/interfaces/class-wc-product-variable-data-store-interface.php
@@ -0,0 +1,83 @@
+ '' - the name of the action that will be triggered.
+ * 'args' => null - the args array that will be passed with the action.
+ * 'date' => null - the scheduled date of the action. Expects a DateTime object, a unix timestamp, or a string that can parsed with strtotime(). Used in UTC timezone.
+ * 'date_compare' => '<=' - operator for testing "date". accepted values are '!=', '>', '>=', '<', '<=', '='.
+ * 'modified' => null - the date the action was last updated. Expects a DateTime object, a unix timestamp, or a string that can parsed with strtotime(). Used in UTC timezone.
+ * 'modified_compare' => '<=' - operator for testing "modified". accepted values are '!=', '>', '>=', '<', '<=', '='.
+ * 'group' => '' - the group the action belongs to.
+ * 'status' => '' - ActionScheduler_Store::STATUS_COMPLETE or ActionScheduler_Store::STATUS_PENDING.
+ * 'claimed' => null - TRUE to find claimed actions, FALSE to find unclaimed actions, a string to find a specific claim ID.
+ * 'per_page' => 5 - Number of results to return.
+ * 'offset' => 0.
+ * 'orderby' => 'date' - accepted values are 'hook', 'group', 'modified', or 'date'.
+ * 'order' => 'ASC'.
+ * @param string $return_format OBJECT, ARRAY_A, or ids.
+ * @return array
+ */
+ public function search( $args = array(), $return_format = OBJECT );
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/interfaces/class-wc-shipping-zone-data-store-interface.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/interfaces/class-wc-shipping-zone-data-store-interface.php
new file mode 100644
index 0000000..7009c5b
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/interfaces/class-wc-shipping-zone-data-store-interface.php
@@ -0,0 +1,85 @@
+set_props( array(
+ 'code' => $code,
+ 'discount' => $discount,
+ 'discount_tax' => $discount_tax,
+ 'order_id' => $this->get_id(),
+ ) );
+ $item->save();
+ $this->add_item( $item );
+ wc_do_deprecated_action( 'woocommerce_order_add_coupon', array( $this->get_id(), $item->get_id(), $code, $discount, $discount_tax ), '3.0', 'woocommerce_new_order_item action instead.' );
+ return $item->get_id();
+ }
+
+ /**
+ * Add a tax row to the order.
+ * @param int $tax_rate_id
+ * @param int $tax_amount amount of tax.
+ * @param int $shipping_tax_amount shipping amount.
+ * @return int order item ID
+ * @throws WC_Data_Exception
+ */
+ public function add_tax( $tax_rate_id, $tax_amount = 0, $shipping_tax_amount = 0 ) {
+ wc_deprecated_function( 'WC_Order::add_tax', '3.0', 'a new WC_Order_Item_Tax object and add to order with WC_Order::add_item()' );
+
+ $item = new WC_Order_Item_Tax();
+ $item->set_props( array(
+ 'rate_id' => $tax_rate_id,
+ 'tax_total' => $tax_amount,
+ 'shipping_tax_total' => $shipping_tax_amount,
+ ) );
+ $item->set_rate( $tax_rate_id );
+ $item->set_order_id( $this->get_id() );
+ $item->save();
+ $this->add_item( $item );
+ wc_do_deprecated_action( 'woocommerce_order_add_tax', array( $this->get_id(), $item->get_id(), $tax_rate_id, $tax_amount, $shipping_tax_amount ), '3.0', 'woocommerce_new_order_item action instead.' );
+ return $item->get_id();
+ }
+
+ /**
+ * Add a shipping row to the order.
+ * @param WC_Shipping_Rate shipping_rate
+ * @return int order item ID
+ * @throws WC_Data_Exception
+ */
+ public function add_shipping( $shipping_rate ) {
+ wc_deprecated_function( 'WC_Order::add_shipping', '3.0', 'a new WC_Order_Item_Shipping object and add to order with WC_Order::add_item()' );
+
+ $item = new WC_Order_Item_Shipping();
+ $item->set_props( array(
+ 'method_title' => $shipping_rate->label,
+ 'method_id' => $shipping_rate->id,
+ 'total' => wc_format_decimal( $shipping_rate->cost ),
+ 'taxes' => $shipping_rate->taxes,
+ 'order_id' => $this->get_id(),
+ ) );
+ foreach ( $shipping_rate->get_meta_data() as $key => $value ) {
+ $item->add_meta_data( $key, $value, true );
+ }
+ $item->save();
+ $this->add_item( $item );
+ wc_do_deprecated_action( 'woocommerce_order_add_shipping', array( $this->get_id(), $item->get_id(), $shipping_rate ), '3.0', 'woocommerce_new_order_item action instead.' );
+ return $item->get_id();
+ }
+
+ /**
+ * Add a fee to the order.
+ * Order must be saved prior to adding items.
+ *
+ * Fee is an amount of money charged for a particular piece of work
+ * or for a particular right or service, and not supposed to be negative.
+ *
+ * @throws WC_Data_Exception
+ * @param object $fee Fee data.
+ * @return int Updated order item ID.
+ */
+ public function add_fee( $fee ) {
+ wc_deprecated_function( 'WC_Order::add_fee', '3.0', 'a new WC_Order_Item_Fee object and add to order with WC_Order::add_item()' );
+
+ $item = new WC_Order_Item_Fee();
+ $item->set_props( array(
+ 'name' => $fee->name,
+ 'tax_class' => $fee->taxable ? $fee->tax_class : 0,
+ 'total' => $fee->amount,
+ 'total_tax' => $fee->tax,
+ 'taxes' => array(
+ 'total' => $fee->tax_data,
+ ),
+ 'order_id' => $this->get_id(),
+ ) );
+ $item->save();
+ $this->add_item( $item );
+ wc_do_deprecated_action( 'woocommerce_order_add_fee', array( $this->get_id(), $item->get_id(), $fee ), '3.0', 'woocommerce_new_order_item action instead.' );
+ return $item->get_id();
+ }
+
+ /**
+ * Update a line item for the order.
+ *
+ * Note this does not update order totals.
+ *
+ * @param object|int $item order item ID or item object.
+ * @param WC_Product $product
+ * @param array $args data to update.
+ * @return int updated order item ID
+ * @throws WC_Data_Exception
+ */
+ public function update_product( $item, $product, $args ) {
+ wc_deprecated_function( 'WC_Order::update_product', '3.0', 'an interaction with the WC_Order_Item_Product class' );
+ if ( is_numeric( $item ) ) {
+ $item = $this->get_item( $item );
+ }
+ if ( ! is_object( $item ) || ! $item->is_type( 'line_item' ) ) {
+ return false;
+ }
+ if ( ! $this->get_id() ) {
+ $this->save(); // Order must exist
+ }
+
+ // BW compatibility with old args
+ if ( isset( $args['totals'] ) ) {
+ foreach ( $args['totals'] as $key => $value ) {
+ if ( 'tax' === $key ) {
+ $args['total_tax'] = $value;
+ } elseif ( 'tax_data' === $key ) {
+ $args['taxes'] = $value;
+ } else {
+ $args[ $key ] = $value;
+ }
+ }
+ }
+
+ // Handle qty if set.
+ if ( isset( $args['qty'] ) ) {
+ if ( $product->backorders_require_notification() && $product->is_on_backorder( $args['qty'] ) ) {
+ $item->add_meta_data( apply_filters( 'woocommerce_backordered_item_meta_name', __( 'Backordered', 'woocommerce' ), $item ), $args['qty'] - max( 0, $product->get_stock_quantity() ), true );
+ }
+ $args['subtotal'] = $args['subtotal'] ? $args['subtotal'] : wc_get_price_excluding_tax( $product, array( 'qty' => $args['qty'] ) );
+ $args['total'] = $args['total'] ? $args['total'] : wc_get_price_excluding_tax( $product, array( 'qty' => $args['qty'] ) );
+ }
+
+ $item->set_order_id( $this->get_id() );
+ $item->set_props( $args );
+ $item->save();
+ do_action( 'woocommerce_order_edit_product', $this->get_id(), $item->get_id(), $args, $product );
+
+ return $item->get_id();
+ }
+
+ /**
+ * Update coupon for order. Note this does not update order totals.
+ * @param object|int $item
+ * @param array $args
+ * @return int updated order item ID
+ * @throws WC_Data_Exception
+ */
+ public function update_coupon( $item, $args ) {
+ wc_deprecated_function( 'WC_Order::update_coupon', '3.0', 'an interaction with the WC_Order_Item_Coupon class' );
+ if ( is_numeric( $item ) ) {
+ $item = $this->get_item( $item );
+ }
+ if ( ! is_object( $item ) || ! $item->is_type( 'coupon' ) ) {
+ return false;
+ }
+ if ( ! $this->get_id() ) {
+ $this->save(); // Order must exist
+ }
+
+ // BW compatibility for old args
+ if ( isset( $args['discount_amount'] ) ) {
+ $args['discount'] = $args['discount_amount'];
+ }
+ if ( isset( $args['discount_amount_tax'] ) ) {
+ $args['discount_tax'] = $args['discount_amount_tax'];
+ }
+
+ $item->set_order_id( $this->get_id() );
+ $item->set_props( $args );
+ $item->save();
+
+ do_action( 'woocommerce_order_update_coupon', $this->get_id(), $item->get_id(), $args );
+
+ return $item->get_id();
+ }
+
+ /**
+ * Update shipping method for order.
+ *
+ * Note this does not update the order total.
+ *
+ * @param object|int $item
+ * @param array $args
+ * @return int updated order item ID
+ * @throws WC_Data_Exception
+ */
+ public function update_shipping( $item, $args ) {
+ wc_deprecated_function( 'WC_Order::update_shipping', '3.0', 'an interaction with the WC_Order_Item_Shipping class' );
+ if ( is_numeric( $item ) ) {
+ $item = $this->get_item( $item );
+ }
+ if ( ! is_object( $item ) || ! $item->is_type( 'shipping' ) ) {
+ return false;
+ }
+ if ( ! $this->get_id() ) {
+ $this->save(); // Order must exist
+ }
+
+ // BW compatibility for old args
+ if ( isset( $args['cost'] ) ) {
+ $args['total'] = $args['cost'];
+ }
+
+ $item->set_order_id( $this->get_id() );
+ $item->set_props( $args );
+ $item->save();
+ $this->calculate_shipping();
+
+ do_action( 'woocommerce_order_update_shipping', $this->get_id(), $item->get_id(), $args );
+
+ return $item->get_id();
+ }
+
+ /**
+ * Update fee for order.
+ *
+ * Note this does not update order totals.
+ *
+ * @param object|int $item
+ * @param array $args
+ * @return int updated order item ID
+ * @throws WC_Data_Exception
+ */
+ public function update_fee( $item, $args ) {
+ wc_deprecated_function( 'WC_Order::update_fee', '3.0', 'an interaction with the WC_Order_Item_Fee class' );
+ if ( is_numeric( $item ) ) {
+ $item = $this->get_item( $item );
+ }
+ if ( ! is_object( $item ) || ! $item->is_type( 'fee' ) ) {
+ return false;
+ }
+ if ( ! $this->get_id() ) {
+ $this->save(); // Order must exist
+ }
+
+ $item->set_order_id( $this->get_id() );
+ $item->set_props( $args );
+ $item->save();
+
+ do_action( 'woocommerce_order_update_fee', $this->get_id(), $item->get_id(), $args );
+
+ return $item->get_id();
+ }
+
+ /**
+ * Update tax line on order.
+ * Note this does not update order totals.
+ *
+ * @since 3.0
+ * @param object|int $item
+ * @param array $args
+ * @return int updated order item ID
+ * @throws WC_Data_Exception
+ */
+ public function update_tax( $item, $args ) {
+ wc_deprecated_function( 'WC_Order::update_tax', '3.0', 'an interaction with the WC_Order_Item_Tax class' );
+ if ( is_numeric( $item ) ) {
+ $item = $this->get_item( $item );
+ }
+ if ( ! is_object( $item ) || ! $item->is_type( 'tax' ) ) {
+ return false;
+ }
+ if ( ! $this->get_id() ) {
+ $this->save(); // Order must exist
+ }
+
+ $item->set_order_id( $this->get_id() );
+ $item->set_props( $args );
+ $item->save();
+
+ do_action( 'woocommerce_order_update_tax', $this->get_id(), $item->get_id(), $args );
+
+ return $item->get_id();
+ }
+
+ /**
+ * Get a product (either product or variation).
+ * @deprecated 4.4.0
+ * @param object $item
+ * @return WC_Product|bool
+ */
+ public function get_product_from_item( $item ) {
+ wc_deprecated_function( 'WC_Abstract_Legacy_Order::get_product_from_item', '4.4.0', '$item->get_product()' );
+ if ( is_callable( array( $item, 'get_product' ) ) ) {
+ $product = $item->get_product();
+ } else {
+ $product = false;
+ }
+ return apply_filters( 'woocommerce_get_product_from_item', $product, $item, $this );
+ }
+
+ /**
+ * Set the customer address.
+ * @param array $address Address data.
+ * @param string $type billing or shipping.
+ */
+ public function set_address( $address, $type = 'billing' ) {
+ foreach ( $address as $key => $value ) {
+ update_post_meta( $this->get_id(), "_{$type}_" . $key, $value );
+ if ( is_callable( array( $this, "set_{$type}_{$key}" ) ) ) {
+ $this->{"set_{$type}_{$key}"}( $value );
+ }
+ }
+ }
+
+ /**
+ * Set an order total.
+ * @param float $amount
+ * @param string $total_type
+ * @return bool
+ */
+ public function legacy_set_total( $amount, $total_type = 'total' ) {
+ if ( ! in_array( $total_type, array( 'shipping', 'tax', 'shipping_tax', 'total', 'cart_discount', 'cart_discount_tax' ) ) ) {
+ return false;
+ }
+
+ switch ( $total_type ) {
+ case 'total' :
+ $amount = wc_format_decimal( $amount, wc_get_price_decimals() );
+ $this->set_total( $amount );
+ update_post_meta( $this->get_id(), '_order_total', $amount );
+ break;
+ case 'cart_discount' :
+ $amount = wc_format_decimal( $amount );
+ $this->set_discount_total( $amount );
+ update_post_meta( $this->get_id(), '_cart_discount', $amount );
+ break;
+ case 'cart_discount_tax' :
+ $amount = wc_format_decimal( $amount );
+ $this->set_discount_tax( $amount );
+ update_post_meta( $this->get_id(), '_cart_discount_tax', $amount );
+ break;
+ case 'shipping' :
+ $amount = wc_format_decimal( $amount );
+ $this->set_shipping_total( $amount );
+ update_post_meta( $this->get_id(), '_order_shipping', $amount );
+ break;
+ case 'shipping_tax' :
+ $amount = wc_format_decimal( $amount );
+ $this->set_shipping_tax( $amount );
+ update_post_meta( $this->get_id(), '_order_shipping_tax', $amount );
+ break;
+ case 'tax' :
+ $amount = wc_format_decimal( $amount );
+ $this->set_cart_tax( $amount );
+ update_post_meta( $this->get_id(), '_order_tax', $amount );
+ break;
+ }
+
+ return true;
+ }
+
+ /**
+ * Magic __isset method for backwards compatibility. Handles legacy properties which could be accessed directly in the past.
+ *
+ * @param string $key
+ * @return bool
+ */
+ public function __isset( $key ) {
+ $legacy_props = array( 'completed_date', 'id', 'order_type', 'post', 'status', 'post_status', 'customer_note', 'customer_message', 'user_id', 'customer_user', 'prices_include_tax', 'tax_display_cart', 'display_totals_ex_tax', 'display_cart_ex_tax', 'order_date', 'modified_date', 'cart_discount', 'cart_discount_tax', 'order_shipping', 'order_shipping_tax', 'order_total', 'order_tax', 'billing_first_name', 'billing_last_name', 'billing_company', 'billing_address_1', 'billing_address_2', 'billing_city', 'billing_state', 'billing_postcode', 'billing_country', 'billing_phone', 'billing_email', 'shipping_first_name', 'shipping_last_name', 'shipping_company', 'shipping_address_1', 'shipping_address_2', 'shipping_city', 'shipping_state', 'shipping_postcode', 'shipping_country', 'customer_ip_address', 'customer_user_agent', 'payment_method_title', 'payment_method', 'order_currency' );
+ return $this->get_id() ? ( in_array( $key, $legacy_props ) || metadata_exists( 'post', $this->get_id(), '_' . $key ) ) : false;
+ }
+
+ /**
+ * Magic __get method for backwards compatibility.
+ *
+ * @param string $key
+ * @return mixed
+ */
+ public function __get( $key ) {
+ wc_doing_it_wrong( $key, 'Order properties should not be accessed directly.', '3.0' );
+
+ if ( 'completed_date' === $key ) {
+ return $this->get_date_completed() ? gmdate( 'Y-m-d H:i:s', $this->get_date_completed()->getOffsetTimestamp() ) : '';
+ } elseif ( 'paid_date' === $key ) {
+ return $this->get_date_paid() ? gmdate( 'Y-m-d H:i:s', $this->get_date_paid()->getOffsetTimestamp() ) : '';
+ } elseif ( 'modified_date' === $key ) {
+ return $this->get_date_modified() ? gmdate( 'Y-m-d H:i:s', $this->get_date_modified()->getOffsetTimestamp() ) : '';
+ } elseif ( 'order_date' === $key ) {
+ return $this->get_date_created() ? gmdate( 'Y-m-d H:i:s', $this->get_date_created()->getOffsetTimestamp() ) : '';
+ } elseif ( 'id' === $key ) {
+ return $this->get_id();
+ } elseif ( 'post' === $key ) {
+ return get_post( $this->get_id() );
+ } elseif ( 'status' === $key ) {
+ return $this->get_status();
+ } elseif ( 'post_status' === $key ) {
+ return get_post_status( $this->get_id() );
+ } elseif ( 'customer_message' === $key || 'customer_note' === $key ) {
+ return $this->get_customer_note();
+ } elseif ( in_array( $key, array( 'user_id', 'customer_user' ) ) ) {
+ return $this->get_customer_id();
+ } elseif ( 'tax_display_cart' === $key ) {
+ return get_option( 'woocommerce_tax_display_cart' );
+ } elseif ( 'display_totals_ex_tax' === $key ) {
+ return 'excl' === get_option( 'woocommerce_tax_display_cart' );
+ } elseif ( 'display_cart_ex_tax' === $key ) {
+ return 'excl' === get_option( 'woocommerce_tax_display_cart' );
+ } elseif ( 'cart_discount' === $key ) {
+ return $this->get_total_discount();
+ } elseif ( 'cart_discount_tax' === $key ) {
+ return $this->get_discount_tax();
+ } elseif ( 'order_tax' === $key ) {
+ return $this->get_cart_tax();
+ } elseif ( 'order_shipping_tax' === $key ) {
+ return $this->get_shipping_tax();
+ } elseif ( 'order_shipping' === $key ) {
+ return $this->get_shipping_total();
+ } elseif ( 'order_total' === $key ) {
+ return $this->get_total();
+ } elseif ( 'order_type' === $key ) {
+ return $this->get_type();
+ } elseif ( 'order_currency' === $key ) {
+ return $this->get_currency();
+ } elseif ( 'order_version' === $key ) {
+ return $this->get_version();
+ } elseif ( is_callable( array( $this, "get_{$key}" ) ) ) {
+ return $this->{"get_{$key}"}();
+ } else {
+ return get_post_meta( $this->get_id(), '_' . $key, true );
+ }
+ }
+
+ /**
+ * has_meta function for order items. This is different to the WC_Data
+ * version and should be removed in future versions.
+ *
+ * @deprecated 3.0
+ *
+ * @param int $order_item_id
+ *
+ * @return array of meta data.
+ */
+ public function has_meta( $order_item_id ) {
+ global $wpdb;
+
+ wc_deprecated_function( 'WC_Order::has_meta( $order_item_id )', '3.0', 'WC_Order_item::get_meta_data' );
+
+ return $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value, meta_id, order_item_id
+ FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id = %d
+ ORDER BY meta_id", absint( $order_item_id ) ), ARRAY_A );
+ }
+
+ /**
+ * Display meta data belonging to an item.
+ * @param array $item
+ */
+ public function display_item_meta( $item ) {
+ wc_deprecated_function( 'WC_Order::display_item_meta', '3.0', 'wc_display_item_meta' );
+ $product = $item->get_product();
+ $item_meta = new WC_Order_Item_Meta( $item, $product );
+ $item_meta->display();
+ }
+
+ /**
+ * Display download links for an order item.
+ * @param array $item
+ */
+ public function display_item_downloads( $item ) {
+ wc_deprecated_function( 'WC_Order::display_item_downloads', '3.0', 'wc_display_item_downloads' );
+ $product = $item->get_product();
+
+ if ( $product && $product->exists() && $product->is_downloadable() && $this->is_download_permitted() ) {
+ $download_files = $this->get_item_downloads( $item );
+ $i = 0;
+ $links = array();
+
+ foreach ( $download_files as $download_id => $file ) {
+ $i++;
+ /* translators: 1: current item count */
+ $prefix = count( $download_files ) > 1 ? sprintf( __( 'Download %d', 'woocommerce' ), $i ) : __( 'Download', 'woocommerce' );
+ $links[] = '' . esc_html( $prefix ) . ': ' . esc_html( $file['name'] ) . '' . "\n";
+ }
+
+ echo '
+
+
+
+
+
+
+
+
' . implode( '
', $links );
+ }
+ }
+
+ /**
+ * Get the Download URL.
+ *
+ * @param int $product_id
+ * @param int $download_id
+ * @return string
+ */
+ public function get_download_url( $product_id, $download_id ) {
+ wc_deprecated_function( 'WC_Order::get_download_url', '3.0', 'WC_Order_Item_Product::get_item_download_url' );
+ return add_query_arg( array(
+ 'download_file' => $product_id,
+ 'order' => $this->get_order_key(),
+ 'email' => urlencode( $this->get_billing_email() ),
+ 'key' => $download_id,
+ ), trailingslashit( home_url() ) );
+ }
+
+ /**
+ * Get the downloadable files for an item in this order.
+ *
+ * @param array $item
+ * @return array
+ */
+ public function get_item_downloads( $item ) {
+ wc_deprecated_function( 'WC_Order::get_item_downloads', '3.0', 'WC_Order_Item_Product::get_item_downloads' );
+
+ if ( ! $item instanceof WC_Order_Item ) {
+ if ( ! empty( $item['variation_id'] ) ) {
+ $product_id = $item['variation_id'];
+ } elseif ( ! empty( $item['product_id'] ) ) {
+ $product_id = $item['product_id'];
+ } else {
+ return array();
+ }
+
+ // Create a 'virtual' order item to allow retrieving item downloads when
+ // an array of product_id is passed instead of actual order item.
+ $item = new WC_Order_Item_Product();
+ $item->set_product( wc_get_product( $product_id ) );
+ $item->set_order_id( $this->get_id() );
+ }
+
+ return $item->get_item_downloads();
+ }
+
+ /**
+ * Gets shipping total. Alias of WC_Order::get_shipping_total().
+ * @deprecated 3.0.0 since this is an alias only.
+ * @return float
+ */
+ public function get_total_shipping() {
+ return $this->get_shipping_total();
+ }
+
+ /**
+ * Get order item meta.
+ * @deprecated 3.0.0
+ * @param mixed $order_item_id
+ * @param string $key (default: '')
+ * @param bool $single (default: false)
+ * @return array|string
+ */
+ public function get_item_meta( $order_item_id, $key = '', $single = false ) {
+ wc_deprecated_function( 'WC_Order::get_item_meta', '3.0', 'wc_get_order_item_meta' );
+ return get_metadata( 'order_item', $order_item_id, $key, $single );
+ }
+
+ /**
+ * Get all item meta data in array format in the order it was saved. Does not group meta by key like get_item_meta().
+ *
+ * @param mixed $order_item_id
+ * @return array of objects
+ */
+ public function get_item_meta_array( $order_item_id ) {
+ wc_deprecated_function( 'WC_Order::get_item_meta_array', '3.0', 'WC_Order_Item::get_meta_data() (note the format has changed)' );
+ $item = $this->get_item( $order_item_id );
+ $meta_data = $item->get_meta_data();
+ $item_meta_array = array();
+
+ foreach ( $meta_data as $meta ) {
+ $item_meta_array[ $meta->id ] = $meta;
+ }
+
+ return $item_meta_array;
+ }
+
+ /**
+ * Get coupon codes only.
+ *
+ * @deprecated 3.7.0 - Replaced with better named method to reflect the actual data being returned.
+ * @return array
+ */
+ public function get_used_coupons() {
+ wc_deprecated_function( 'get_used_coupons', '3.7', 'WC_Abstract_Order::get_coupon_codes' );
+ return $this->get_coupon_codes();
+ }
+
+ /**
+ * Expand item meta into the $item array.
+ * @deprecated 3.0.0 Item meta no longer expanded due to new order item
+ * classes. This function now does nothing to avoid data breakage.
+ * @param array $item before expansion.
+ * @return array
+ */
+ public function expand_item_meta( $item ) {
+ wc_deprecated_function( 'WC_Order::expand_item_meta', '3.0' );
+ return $item;
+ }
+
+ /**
+ * Load the order object. Called from the constructor.
+ * @deprecated 3.0.0 Logic moved to constructor
+ * @param int|object|WC_Order $order Order to init.
+ */
+ protected function init( $order ) {
+ wc_deprecated_function( 'WC_Order::init', '3.0', 'Logic moved to constructor' );
+ if ( is_numeric( $order ) ) {
+ $this->set_id( $order );
+ } elseif ( $order instanceof WC_Order ) {
+ $this->set_id( absint( $order->get_id() ) );
+ } elseif ( isset( $order->ID ) ) {
+ $this->set_id( absint( $order->ID ) );
+ }
+ $this->set_object_read( false );
+ $this->data_store->read( $this );
+ }
+
+ /**
+ * Gets an order from the database.
+ * @deprecated 3.0
+ * @param int $id (default: 0).
+ * @return bool
+ */
+ public function get_order( $id = 0 ) {
+ wc_deprecated_function( 'WC_Order::get_order', '3.0' );
+
+ if ( ! $id ) {
+ return false;
+ }
+
+ $result = get_post( $id );
+
+ if ( $result ) {
+ $this->populate( $result );
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Populates an order from the loaded post data.
+ * @deprecated 3.0
+ * @param mixed $result
+ */
+ public function populate( $result ) {
+ wc_deprecated_function( 'WC_Order::populate', '3.0' );
+ $this->set_id( $result->ID );
+ $this->set_object_read( false );
+ $this->data_store->read( $this );
+ }
+
+ /**
+ * Cancel the order and restore the cart (before payment).
+ * @deprecated 3.0.0 Moved to event handler.
+ * @param string $note (default: '') Optional note to add.
+ */
+ public function cancel_order( $note = '' ) {
+ wc_deprecated_function( 'WC_Order::cancel_order', '3.0', 'WC_Order::update_status' );
+ WC()->session->set( 'order_awaiting_payment', false );
+ $this->update_status( 'cancelled', $note );
+ }
+
+ /**
+ * Record sales.
+ * @deprecated 3.0.0
+ */
+ public function record_product_sales() {
+ wc_deprecated_function( 'WC_Order::record_product_sales', '3.0', 'wc_update_total_sales_counts' );
+ wc_update_total_sales_counts( $this->get_id() );
+ }
+
+ /**
+ * Increase applied coupon counts.
+ * @deprecated 3.0.0
+ */
+ public function increase_coupon_usage_counts() {
+ wc_deprecated_function( 'WC_Order::increase_coupon_usage_counts', '3.0', 'wc_update_coupon_usage_counts' );
+ wc_update_coupon_usage_counts( $this->get_id() );
+ }
+
+ /**
+ * Decrease applied coupon counts.
+ * @deprecated 3.0.0
+ */
+ public function decrease_coupon_usage_counts() {
+ wc_deprecated_function( 'WC_Order::decrease_coupon_usage_counts', '3.0', 'wc_update_coupon_usage_counts' );
+ wc_update_coupon_usage_counts( $this->get_id() );
+ }
+
+ /**
+ * Reduce stock levels for all line items in the order.
+ * @deprecated 3.0.0
+ */
+ public function reduce_order_stock() {
+ wc_deprecated_function( 'WC_Order::reduce_order_stock', '3.0', 'wc_reduce_stock_levels' );
+ wc_reduce_stock_levels( $this->get_id() );
+ }
+
+ /**
+ * Send the stock notifications.
+ * @deprecated 3.0.0 No longer needs to be called directly.
+ *
+ * @param $product
+ * @param $new_stock
+ * @param $qty_ordered
+ */
+ public function send_stock_notifications( $product, $new_stock, $qty_ordered ) {
+ wc_deprecated_function( 'WC_Order::send_stock_notifications', '3.0' );
+ }
+
+ /**
+ * Output items for display in html emails.
+ * @deprecated 3.0.0 Moved to template functions.
+ * @param array $args Items args.
+ * @return string
+ */
+ public function email_order_items_table( $args = array() ) {
+ wc_deprecated_function( 'WC_Order::email_order_items_table', '3.0', 'wc_get_email_order_items' );
+ return wc_get_email_order_items( $this, $args );
+ }
+
+ /**
+ * Get currency.
+ * @deprecated 3.0.0
+ */
+ public function get_order_currency() {
+ wc_deprecated_function( 'WC_Order::get_order_currency', '3.0', 'WC_Order::get_currency' );
+ return apply_filters( 'woocommerce_get_order_currency', $this->get_currency(), $this );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/abstract-wc-legacy-payment-token.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/abstract-wc-legacy-payment-token.php
new file mode 100644
index 0000000..ed7201a
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/abstract-wc-legacy-payment-token.php
@@ -0,0 +1,70 @@
+read, ->update or ->create
+ * directly on the object.
+ *
+ * @version 3.0.0
+ * @package WooCommerce\Classes
+ * @category Class
+ * @author WooCommerce
+ */
+abstract class WC_Legacy_Payment_Token extends WC_Data {
+
+ /**
+ * Sets the type of this payment token (CC, eCheck, or something else).
+ *
+ * @param string Payment Token Type (CC, eCheck)
+ */
+ public function set_type( $type ) {
+ wc_deprecated_function( 'WC_Payment_Token::set_type', '3.0.0', 'Type cannot be overwritten.' );
+ }
+
+ /**
+ * Read a token by ID.
+ * @deprecated 3.0.0 - Init a token class with an ID.
+ *
+ * @param int $token_id
+ */
+ public function read( $token_id ) {
+ wc_deprecated_function( 'WC_Payment_Token::read', '3.0.0', 'a new token class initialized with an ID.' );
+ $this->set_id( $token_id );
+ $data_store = WC_Data_Store::load( 'payment-token' );
+ $data_store->read( $this );
+ }
+
+ /**
+ * Update a token.
+ * @deprecated 3.0.0 - Use ::save instead.
+ */
+ public function update() {
+ wc_deprecated_function( 'WC_Payment_Token::update', '3.0.0', 'WC_Payment_Token::save instead.' );
+ $data_store = WC_Data_Store::load( 'payment-token' );
+ try {
+ $data_store->update( $this );
+ } catch ( Exception $e ) {
+ return false;
+ }
+ }
+
+ /**
+ * Create a token.
+ * @deprecated 3.0.0 - Use ::save instead.
+ */
+ public function create() {
+ wc_deprecated_function( 'WC_Payment_Token::create', '3.0.0', 'WC_Payment_Token::save instead.' );
+ $data_store = WC_Data_Store::load( 'payment-token' );
+ try {
+ $data_store->create( $this );
+ } catch ( Exception $e ) {
+ return false;
+ }
+ }
+
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/abstract-wc-legacy-product.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/abstract-wc-legacy-product.php
new file mode 100644
index 0000000..97f370e
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/abstract-wc-legacy-product.php
@@ -0,0 +1,692 @@
+is_type( 'variation' ) ) {
+ $valid = array_merge( $valid, array(
+ 'variation_id',
+ 'variation_data',
+ 'variation_has_stock',
+ 'variation_shipping_class_id',
+ 'variation_has_sku',
+ 'variation_has_length',
+ 'variation_has_width',
+ 'variation_has_height',
+ 'variation_has_weight',
+ 'variation_has_tax_class',
+ 'variation_has_downloadable_files',
+ ) );
+ }
+ return in_array( $key, array_merge( $valid, array_keys( $this->data ) ) ) || metadata_exists( 'post', $this->get_id(), '_' . $key ) || metadata_exists( 'post', $this->get_parent_id(), '_' . $key );
+ }
+
+ /**
+ * Magic __get method for backwards compatibility. Maps legacy vars to new getters.
+ *
+ * @param string $key Key name.
+ * @return mixed
+ */
+ public function __get( $key ) {
+
+ if ( 'post_type' === $key ) {
+ return $this->post_type;
+ }
+
+ wc_doing_it_wrong( $key, __( 'Product properties should not be accessed directly.', 'woocommerce' ), '3.0' );
+
+ switch ( $key ) {
+ case 'id' :
+ $value = $this->is_type( 'variation' ) ? $this->get_parent_id() : $this->get_id();
+ break;
+ case 'product_type' :
+ $value = $this->get_type();
+ break;
+ case 'product_attributes' :
+ $value = isset( $this->data['attributes'] ) ? $this->data['attributes'] : '';
+ break;
+ case 'visibility' :
+ $value = $this->get_catalog_visibility();
+ break;
+ case 'sale_price_dates_from' :
+ return $this->get_date_on_sale_from() ? $this->get_date_on_sale_from()->getTimestamp() : '';
+ break;
+ case 'sale_price_dates_to' :
+ return $this->get_date_on_sale_to() ? $this->get_date_on_sale_to()->getTimestamp() : '';
+ break;
+ case 'post' :
+ $value = get_post( $this->get_id() );
+ break;
+ case 'download_type' :
+ return 'standard';
+ break;
+ case 'product_image_gallery' :
+ $value = $this->get_gallery_image_ids();
+ break;
+ case 'variation_shipping_class' :
+ case 'shipping_class' :
+ $value = $this->get_shipping_class();
+ break;
+ case 'total_stock' :
+ $value = $this->get_total_stock();
+ break;
+ case 'downloadable' :
+ case 'virtual' :
+ case 'manage_stock' :
+ case 'featured' :
+ case 'sold_individually' :
+ $value = $this->{"get_$key"}() ? 'yes' : 'no';
+ break;
+ case 'crosssell_ids' :
+ $value = $this->get_cross_sell_ids();
+ break;
+ case 'upsell_ids' :
+ $value = $this->get_upsell_ids();
+ break;
+ case 'parent' :
+ $value = wc_get_product( $this->get_parent_id() );
+ break;
+ case 'variation_id' :
+ $value = $this->is_type( 'variation' ) ? $this->get_id() : '';
+ break;
+ case 'variation_data' :
+ $value = $this->is_type( 'variation' ) ? wc_get_product_variation_attributes( $this->get_id() ) : '';
+ break;
+ case 'variation_has_stock' :
+ $value = $this->is_type( 'variation' ) ? $this->managing_stock() : '';
+ break;
+ case 'variation_shipping_class_id' :
+ $value = $this->is_type( 'variation' ) ? $this->get_shipping_class_id() : '';
+ break;
+ case 'variation_has_sku' :
+ case 'variation_has_length' :
+ case 'variation_has_width' :
+ case 'variation_has_height' :
+ case 'variation_has_weight' :
+ case 'variation_has_tax_class' :
+ case 'variation_has_downloadable_files' :
+ $value = true; // These were deprecated in 2.2 and simply returned true in 2.6.x.
+ break;
+ default :
+ if ( in_array( $key, array_keys( $this->data ) ) ) {
+ $value = $this->{"get_$key"}();
+ } else {
+ $value = get_post_meta( $this->id, '_' . $key, true );
+ }
+ break;
+ }
+ return $value;
+ }
+
+ /**
+ * If set, get the default attributes for a variable product.
+ *
+ * @deprecated 3.0.0
+ * @return array
+ */
+ public function get_variation_default_attributes() {
+ wc_deprecated_function( 'WC_Product_Variable::get_variation_default_attributes', '3.0', 'WC_Product::get_default_attributes' );
+ return apply_filters( 'woocommerce_product_default_attributes', $this->get_default_attributes(), $this );
+ }
+
+ /**
+ * Returns the gallery attachment ids.
+ *
+ * @deprecated 3.0.0
+ * @return array
+ */
+ public function get_gallery_attachment_ids() {
+ wc_deprecated_function( 'WC_Product::get_gallery_attachment_ids', '3.0', 'WC_Product::get_gallery_image_ids' );
+ return $this->get_gallery_image_ids();
+ }
+
+ /**
+ * Set stock level of the product.
+ *
+ * @deprecated 3.0.0
+ *
+ * @param int $amount
+ * @param string $mode
+ *
+ * @return int
+ */
+ public function set_stock( $amount = null, $mode = 'set' ) {
+ wc_deprecated_function( 'WC_Product::set_stock', '3.0', 'wc_update_product_stock' );
+ return wc_update_product_stock( $this, $amount, $mode );
+ }
+
+ /**
+ * Reduce stock level of the product.
+ *
+ * @deprecated 3.0.0
+ * @param int $amount Amount to reduce by. Default: 1
+ * @return int new stock level
+ */
+ public function reduce_stock( $amount = 1 ) {
+ wc_deprecated_function( 'WC_Product::reduce_stock', '3.0', 'wc_update_product_stock' );
+ return wc_update_product_stock( $this, $amount, 'decrease' );
+ }
+
+ /**
+ * Increase stock level of the product.
+ *
+ * @deprecated 3.0.0
+ * @param int $amount Amount to increase by. Default 1.
+ * @return int new stock level
+ */
+ public function increase_stock( $amount = 1 ) {
+ wc_deprecated_function( 'WC_Product::increase_stock', '3.0', 'wc_update_product_stock' );
+ return wc_update_product_stock( $this, $amount, 'increase' );
+ }
+
+ /**
+ * Check if the stock status needs changing.
+ *
+ * @deprecated 3.0.0 Sync is done automatically on read/save, so calling this should not be needed any more.
+ */
+ public function check_stock_status() {
+ wc_deprecated_function( 'WC_Product::check_stock_status', '3.0' );
+ }
+
+ /**
+ * Get and return related products.
+ * @deprecated 3.0.0 Use wc_get_related_products instead.
+ *
+ * @param int $limit
+ *
+ * @return array
+ */
+ public function get_related( $limit = 5 ) {
+ wc_deprecated_function( 'WC_Product::get_related', '3.0', 'wc_get_related_products' );
+ return wc_get_related_products( $this->get_id(), $limit );
+ }
+
+ /**
+ * Retrieves related product terms.
+ * @deprecated 3.0.0 Use wc_get_product_term_ids instead.
+ *
+ * @param $term
+ *
+ * @return array
+ */
+ protected function get_related_terms( $term ) {
+ wc_deprecated_function( 'WC_Product::get_related_terms', '3.0', 'wc_get_product_term_ids' );
+ return array_merge( array( 0 ), wc_get_product_term_ids( $this->get_id(), $term ) );
+ }
+
+ /**
+ * Builds the related posts query.
+ * @deprecated 3.0.0 Use Product Data Store get_related_products_query instead.
+ *
+ * @param $cats_array
+ * @param $tags_array
+ * @param $exclude_ids
+ * @param $limit
+ */
+ protected function build_related_query( $cats_array, $tags_array, $exclude_ids, $limit ) {
+ wc_deprecated_function( 'WC_Product::build_related_query', '3.0', 'Product Data Store get_related_products_query' );
+ $data_store = WC_Data_Store::load( 'product' );
+ return $data_store->get_related_products_query( $cats_array, $tags_array, $exclude_ids, $limit );
+ }
+
+ /**
+ * Returns the child product.
+ * @deprecated 3.0.0 Use wc_get_product instead.
+ * @param mixed $child_id
+ * @return WC_Product|WC_Product|WC_Product_variation
+ */
+ public function get_child( $child_id ) {
+ wc_deprecated_function( 'WC_Product::get_child', '3.0', 'wc_get_product' );
+ return wc_get_product( $child_id );
+ }
+
+ /**
+ * Functions for getting parts of a price, in html, used by get_price_html.
+ *
+ * @deprecated 3.0.0
+ * @return string
+ */
+ public function get_price_html_from_text() {
+ wc_deprecated_function( 'WC_Product::get_price_html_from_text', '3.0', 'wc_get_price_html_from_text' );
+ return wc_get_price_html_from_text();
+ }
+
+ /**
+ * Functions for getting parts of a price, in html, used by get_price_html.
+ *
+ * @deprecated 3.0.0 Use wc_format_sale_price instead.
+ * @param string $from String or float to wrap with 'from' text
+ * @param mixed $to String or float to wrap with 'to' text
+ * @return string
+ */
+ public function get_price_html_from_to( $from, $to ) {
+ wc_deprecated_function( 'WC_Product::get_price_html_from_to', '3.0', 'wc_format_sale_price' );
+ return apply_filters( 'woocommerce_get_price_html_from_to', wc_format_sale_price( $from, $to ), $from, $to, $this );
+ }
+
+ /**
+ * Lists a table of attributes for the product page.
+ * @deprecated 3.0.0 Use wc_display_product_attributes instead.
+ */
+ public function list_attributes() {
+ wc_deprecated_function( 'WC_Product::list_attributes', '3.0', 'wc_display_product_attributes' );
+ wc_display_product_attributes( $this );
+ }
+
+ /**
+ * Returns the price (including tax). Uses customer tax rates. Can work for a specific $qty for more accurate taxes.
+ *
+ * @deprecated 3.0.0 Use wc_get_price_including_tax instead.
+ * @param int $qty
+ * @param string $price to calculate, left blank to just use get_price()
+ * @return string
+ */
+ public function get_price_including_tax( $qty = 1, $price = '' ) {
+ wc_deprecated_function( 'WC_Product::get_price_including_tax', '3.0', 'wc_get_price_including_tax' );
+ return wc_get_price_including_tax( $this, array( 'qty' => $qty, 'price' => $price ) );
+ }
+
+ /**
+ * Returns the price including or excluding tax, based on the 'woocommerce_tax_display_shop' setting.
+ *
+ * @deprecated 3.0.0 Use wc_get_price_to_display instead.
+ * @param string $price to calculate, left blank to just use get_price()
+ * @param integer $qty passed on to get_price_including_tax() or get_price_excluding_tax()
+ * @return string
+ */
+ public function get_display_price( $price = '', $qty = 1 ) {
+ wc_deprecated_function( 'WC_Product::get_display_price', '3.0', 'wc_get_price_to_display' );
+ return wc_get_price_to_display( $this, array( 'qty' => $qty, 'price' => $price ) );
+ }
+
+ /**
+ * Returns the price (excluding tax) - ignores tax_class filters since the price may *include* tax and thus needs subtracting.
+ * Uses store base tax rates. Can work for a specific $qty for more accurate taxes.
+ *
+ * @deprecated 3.0.0 Use wc_get_price_excluding_tax instead.
+ * @param int $qty
+ * @param string $price to calculate, left blank to just use get_price()
+ * @return string
+ */
+ public function get_price_excluding_tax( $qty = 1, $price = '' ) {
+ wc_deprecated_function( 'WC_Product::get_price_excluding_tax', '3.0', 'wc_get_price_excluding_tax' );
+ return wc_get_price_excluding_tax( $this, array( 'qty' => $qty, 'price' => $price ) );
+ }
+
+ /**
+ * Adjust a products price dynamically.
+ *
+ * @deprecated 3.0.0
+ * @param mixed $price
+ */
+ public function adjust_price( $price ) {
+ wc_deprecated_function( 'WC_Product::adjust_price', '3.0', 'WC_Product::set_price / WC_Product::get_price' );
+ $this->data['price'] = $this->data['price'] + $price;
+ }
+
+ /**
+ * Returns the product categories.
+ *
+ * @deprecated 3.0.0
+ * @param string $sep (default: ', ').
+ * @param string $before (default: '').
+ * @param string $after (default: '').
+ * @return string
+ */
+ public function get_categories( $sep = ', ', $before = '', $after = '' ) {
+ wc_deprecated_function( 'WC_Product::get_categories', '3.0', 'wc_get_product_category_list' );
+ return wc_get_product_category_list( $this->get_id(), $sep, $before, $after );
+ }
+
+ /**
+ * Returns the product tags.
+ *
+ * @deprecated 3.0.0
+ * @param string $sep (default: ', ').
+ * @param string $before (default: '').
+ * @param string $after (default: '').
+ * @return array
+ */
+ public function get_tags( $sep = ', ', $before = '', $after = '' ) {
+ wc_deprecated_function( 'WC_Product::get_tags', '3.0', 'wc_get_product_tag_list' );
+ return wc_get_product_tag_list( $this->get_id(), $sep, $before, $after );
+ }
+
+ /**
+ * Get the product's post data.
+ *
+ * @deprecated 3.0.0
+ * @return WP_Post
+ */
+ public function get_post_data() {
+ wc_deprecated_function( 'WC_Product::get_post_data', '3.0', 'get_post' );
+
+ // In order to keep backwards compatibility it's required to use the parent data for variations.
+ if ( $this->is_type( 'variation' ) ) {
+ $post_data = get_post( $this->get_parent_id() );
+ } else {
+ $post_data = get_post( $this->get_id() );
+ }
+
+ return $post_data;
+ }
+
+ /**
+ * Get the parent of the post.
+ *
+ * @deprecated 3.0.0
+ * @return int
+ */
+ public function get_parent() {
+ wc_deprecated_function( 'WC_Product::get_parent', '3.0', 'WC_Product::get_parent_id' );
+ return apply_filters( 'woocommerce_product_parent', absint( $this->get_post_data()->post_parent ), $this );
+ }
+
+ /**
+ * Returns the upsell product ids.
+ *
+ * @deprecated 3.0.0
+ * @return array
+ */
+ public function get_upsells() {
+ wc_deprecated_function( 'WC_Product::get_upsells', '3.0', 'WC_Product::get_upsell_ids' );
+ return apply_filters( 'woocommerce_product_upsell_ids', $this->get_upsell_ids(), $this );
+ }
+
+ /**
+ * Returns the cross sell product ids.
+ *
+ * @deprecated 3.0.0
+ * @return array
+ */
+ public function get_cross_sells() {
+ wc_deprecated_function( 'WC_Product::get_cross_sells', '3.0', 'WC_Product::get_cross_sell_ids' );
+ return apply_filters( 'woocommerce_product_crosssell_ids', $this->get_cross_sell_ids(), $this );
+ }
+
+ /**
+ * Check if variable product has default attributes set.
+ *
+ * @deprecated 3.0.0
+ * @return bool
+ */
+ public function has_default_attributes() {
+ wc_deprecated_function( 'WC_Product_Variable::has_default_attributes', '3.0', 'a check against WC_Product::get_default_attributes directly' );
+ if ( ! $this->get_default_attributes() ) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Get variation ID.
+ *
+ * @deprecated 3.0.0
+ * @return int
+ */
+ public function get_variation_id() {
+ wc_deprecated_function( 'WC_Product::get_variation_id', '3.0', 'WC_Product::get_id(). It will always be the variation ID if this is a variation.' );
+ return $this->get_id();
+ }
+
+ /**
+ * Get product variation description.
+ *
+ * @deprecated 3.0.0
+ * @return string
+ */
+ public function get_variation_description() {
+ wc_deprecated_function( 'WC_Product::get_variation_description', '3.0', 'WC_Product::get_description()' );
+ return $this->get_description();
+ }
+
+ /**
+ * Check if all variation's attributes are set.
+ *
+ * @deprecated 3.0.0
+ * @return boolean
+ */
+ public function has_all_attributes_set() {
+ wc_deprecated_function( 'WC_Product::has_all_attributes_set', '3.0', 'an array filter on get_variation_attributes for a quick solution.' );
+ $set = true;
+
+ // undefined attributes have null strings as array values
+ foreach ( $this->get_variation_attributes() as $att ) {
+ if ( ! $att ) {
+ $set = false;
+ break;
+ }
+ }
+ return $set;
+ }
+
+ /**
+ * Returns whether or not the variations parent is visible.
+ *
+ * @deprecated 3.0.0
+ * @return bool
+ */
+ public function parent_is_visible() {
+ wc_deprecated_function( 'WC_Product::parent_is_visible', '3.0' );
+ return $this->is_visible();
+ }
+
+ /**
+ * Get total stock - This is the stock of parent and children combined.
+ *
+ * @deprecated 3.0.0
+ * @return int
+ */
+ public function get_total_stock() {
+ wc_deprecated_function( 'WC_Product::get_total_stock', '3.0', 'get_stock_quantity on each child. Beware of performance issues in doing so.' );
+ if ( sizeof( $this->get_children() ) > 0 ) {
+ $total_stock = max( 0, $this->get_stock_quantity() );
+
+ foreach ( $this->get_children() as $child_id ) {
+ if ( 'yes' === get_post_meta( $child_id, '_manage_stock', true ) ) {
+ $stock = get_post_meta( $child_id, '_stock', true );
+ $total_stock += max( 0, wc_stock_amount( $stock ) );
+ }
+ }
+ } else {
+ $total_stock = $this->get_stock_quantity();
+ }
+ return wc_stock_amount( $total_stock );
+ }
+
+ /**
+ * Get formatted variation data with WC < 2.4 back compat and proper formatting of text-based attribute names.
+ *
+ * @deprecated 3.0.0
+ *
+ * @param bool $flat
+ *
+ * @return string
+ */
+ public function get_formatted_variation_attributes( $flat = false ) {
+ wc_deprecated_function( 'WC_Product::get_formatted_variation_attributes', '3.0', 'wc_get_formatted_variation' );
+ return wc_get_formatted_variation( $this, $flat );
+ }
+
+ /**
+ * Sync variable product prices with the children lowest/highest prices.
+ *
+ * @deprecated 3.0.0 not used in core.
+ *
+ * @param int $product_id
+ */
+ public function variable_product_sync( $product_id = 0 ) {
+ wc_deprecated_function( 'WC_Product::variable_product_sync', '3.0' );
+ if ( empty( $product_id ) ) {
+ $product_id = $this->get_id();
+ }
+
+ // Sync prices with children
+ if ( is_callable( array( __CLASS__, 'sync' ) ) ) {
+ self::sync( $product_id );
+ }
+ }
+
+ /**
+ * Sync the variable product's attributes with the variations.
+ *
+ * @param $product
+ * @param bool $children
+ */
+ public static function sync_attributes( $product, $children = false ) {
+ if ( ! is_a( $product, 'WC_Product' ) ) {
+ $product = wc_get_product( $product );
+ }
+
+ /**
+ * Pre 2.4 handling where 'slugs' were saved instead of the full text attribute.
+ * Attempt to get full version of the text attribute from the parent and UPDATE meta.
+ */
+ if ( version_compare( get_post_meta( $product->get_id(), '_product_version', true ), '2.4.0', '<' ) ) {
+ $parent_attributes = array_filter( (array) get_post_meta( $product->get_id(), '_product_attributes', true ) );
+
+ if ( ! $children ) {
+ $children = $product->get_children( 'edit' );
+ }
+
+ foreach ( $children as $child_id ) {
+ $all_meta = get_post_meta( $child_id );
+
+ foreach ( $all_meta as $name => $value ) {
+ if ( 0 !== strpos( $name, 'attribute_' ) ) {
+ continue;
+ }
+ if ( sanitize_title( $value[0] ) === $value[0] ) {
+ foreach ( $parent_attributes as $attribute ) {
+ if ( 'attribute_' . sanitize_title( $attribute['name'] ) !== $name ) {
+ continue;
+ }
+ $text_attributes = wc_get_text_attributes( $attribute['value'] );
+ foreach ( $text_attributes as $text_attribute ) {
+ if ( sanitize_title( $text_attribute ) === $value[0] ) {
+ update_post_meta( $child_id, $name, $text_attribute );
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Match a variation to a given set of attributes using a WP_Query.
+ * @deprecated 3.0.0 in favour of Product data store's find_matching_product_variation.
+ *
+ * @param array $match_attributes
+ */
+ public function get_matching_variation( $match_attributes = array() ) {
+ wc_deprecated_function( 'WC_Product::get_matching_variation', '3.0', 'Product data store find_matching_product_variation' );
+ $data_store = WC_Data_Store::load( 'product' );
+ return $data_store->find_matching_product_variation( $this, $match_attributes );
+ }
+
+ /**
+ * Returns whether or not we are showing dimensions on the product page.
+ * @deprecated 3.0.0 Unused.
+ * @return bool
+ */
+ public function enable_dimensions_display() {
+ wc_deprecated_function( 'WC_Product::enable_dimensions_display', '3.0' );
+ return apply_filters( 'wc_product_enable_dimensions_display', true ) && ( $this->has_dimensions() || $this->has_weight() || $this->child_has_weight() || $this->child_has_dimensions() );
+ }
+
+ /**
+ * Returns the product rating in html format.
+ *
+ * @deprecated 3.0.0
+ * @param string $rating (default: '')
+ * @return string
+ */
+ public function get_rating_html( $rating = null ) {
+ wc_deprecated_function( 'WC_Product::get_rating_html', '3.0', 'wc_get_rating_html' );
+ return wc_get_rating_html( $rating );
+ }
+
+ /**
+ * Sync product rating. Can be called statically.
+ *
+ * @deprecated 3.0.0
+ * @param int $post_id
+ */
+ public static function sync_average_rating( $post_id ) {
+ wc_deprecated_function( 'WC_Product::sync_average_rating', '3.0', 'WC_Comments::get_average_rating_for_product or leave to CRUD.' );
+ // See notes in https://github.com/woocommerce/woocommerce/pull/22909#discussion_r262393401.
+ // Sync count first like in the original method https://github.com/woocommerce/woocommerce/blob/2.6.0/includes/abstracts/abstract-wc-product.php#L1101-L1128.
+ self::sync_rating_count( $post_id );
+ $average = WC_Comments::get_average_rating_for_product( wc_get_product( $post_id ) );
+ update_post_meta( $post_id, '_wc_average_rating', $average );
+ }
+
+ /**
+ * Sync product rating count. Can be called statically.
+ *
+ * @deprecated 3.0.0
+ * @param int $post_id
+ */
+ public static function sync_rating_count( $post_id ) {
+ wc_deprecated_function( 'WC_Product::sync_rating_count', '3.0', 'WC_Comments::get_rating_counts_for_product or leave to CRUD.' );
+ $counts = WC_Comments::get_rating_counts_for_product( wc_get_product( $post_id ) );
+ update_post_meta( $post_id, '_wc_rating_count', $counts );
+ }
+
+ /**
+ * Same as get_downloads in CRUD.
+ *
+ * @deprecated 3.0.0
+ * @return array
+ */
+ public function get_files() {
+ wc_deprecated_function( 'WC_Product::get_files', '3.0', 'WC_Product::get_downloads' );
+ return $this->get_downloads();
+ }
+
+ /**
+ * @deprecated 3.0.0 Sync is taken care of during save - no need to call this directly.
+ */
+ public function grouped_product_sync() {
+ wc_deprecated_function( 'WC_Product::grouped_product_sync', '3.0' );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/class-wc-rest-legacy-coupons-controller.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/class-wc-rest-legacy-coupons-controller.php
new file mode 100644
index 0000000..dc88a4c
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/class-wc-rest-legacy-coupons-controller.php
@@ -0,0 +1,164 @@
+ID );
+ $data = $coupon->get_data();
+
+ $format_decimal = array( 'amount', 'minimum_amount', 'maximum_amount' );
+ $format_date = array( 'date_created', 'date_modified', 'date_expires' );
+ $format_null = array( 'usage_limit', 'usage_limit_per_user', 'limit_usage_to_x_items' );
+
+ // Format decimal values.
+ foreach ( $format_decimal as $key ) {
+ $data[ $key ] = wc_format_decimal( $data[ $key ], 2 );
+ }
+
+ // Format date values.
+ foreach ( $format_date as $key ) {
+ $data[ $key ] = $data[ $key ] ? wc_rest_prepare_date_response( get_gmt_from_date( date( 'Y-m-d H:i:s', $data[ $key ] ) ) ) : null;
+ }
+
+ // Format null values.
+ foreach ( $format_null as $key ) {
+ $data[ $key ] = $data[ $key ] ? $data[ $key ] : null;
+ }
+
+ $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
+ $data = $this->add_additional_fields_to_object( $data, $request );
+ $data = $this->filter_response_by_context( $data, $context );
+ $response = rest_ensure_response( $data );
+ $response->add_links( $this->prepare_links( $post, $request ) );
+
+ /**
+ * Filter the data for a response.
+ *
+ * The dynamic portion of the hook name, $this->post_type, refers to post_type of the post being
+ * prepared for the response.
+ *
+ * @param WP_REST_Response $response The response object.
+ * @param WP_Post $post Post object.
+ * @param WP_REST_Request $request Request object.
+ */
+ return apply_filters( "woocommerce_rest_prepare_{$this->post_type}", $response, $post, $request );
+ }
+
+ /**
+ * Prepare a single coupon for create or update.
+ *
+ * @deprecated 3.0.0
+ *
+ * @param WP_REST_Request $request Request object.
+ * @return WP_Error|stdClass $data Post object.
+ */
+ protected function prepare_item_for_database( $request ) {
+ global $wpdb;
+
+ $id = isset( $request['id'] ) ? absint( $request['id'] ) : 0;
+ $coupon = new WC_Coupon( $id );
+ $schema = $this->get_item_schema();
+ $data_keys = array_keys( array_filter( $schema['properties'], array( $this, 'filter_writable_props' ) ) );
+
+ // Validate required POST fields.
+ if ( 'POST' === $request->get_method() && 0 === $coupon->get_id() ) {
+ if ( empty( $request['code'] ) ) {
+ return new WP_Error( 'woocommerce_rest_empty_coupon_code', sprintf( __( 'The coupon code cannot be empty.', 'woocommerce' ), 'code' ), array( 'status' => 400 ) );
+ }
+ }
+
+ // Handle all writable props.
+ foreach ( $data_keys as $key ) {
+ $value = $request[ $key ];
+
+ if ( ! is_null( $value ) ) {
+ switch ( $key ) {
+ case 'code' :
+ $coupon_code = wc_format_coupon_code( $value );
+ $id = $coupon->get_id() ? $coupon->get_id() : 0;
+ $id_from_code = wc_get_coupon_id_by_code( $coupon_code, $id );
+
+ if ( $id_from_code ) {
+ return new WP_Error( 'woocommerce_rest_coupon_code_already_exists', __( 'The coupon code already exists', 'woocommerce' ), array( 'status' => 400 ) );
+ }
+
+ $coupon->set_code( $coupon_code );
+ break;
+ case 'meta_data' :
+ if ( is_array( $value ) ) {
+ foreach ( $value as $meta ) {
+ $coupon->update_meta_data( $meta['key'], $meta['value'], isset( $meta['id'] ) ? $meta['id'] : '' );
+ }
+ }
+ break;
+ case 'description' :
+ $coupon->set_description( wp_filter_post_kses( $value ) );
+ break;
+ default :
+ if ( is_callable( array( $coupon, "set_{$key}" ) ) ) {
+ $coupon->{"set_{$key}"}( $value );
+ }
+ break;
+ }
+ }
+ }
+
+ /**
+ * Filter the query_vars used in `get_items` for the constructed query.
+ *
+ * The dynamic portion of the hook name, $this->post_type, refers to post_type of the post being
+ * prepared for insertion.
+ *
+ * @param WC_Coupon $coupon The coupon object.
+ * @param WP_REST_Request $request Request object.
+ */
+ return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}", $coupon, $request );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/class-wc-rest-legacy-orders-controller.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/class-wc-rest-legacy-orders-controller.php
new file mode 100644
index 0000000..d96849c
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/class-wc-rest-legacy-orders-controller.php
@@ -0,0 +1,306 @@
+ '_customer_user',
+ 'value' => $request['customer'],
+ 'type' => 'NUMERIC',
+ );
+ }
+
+ // Search by product.
+ if ( ! empty( $request['product'] ) ) {
+ $order_ids = $wpdb->get_col( $wpdb->prepare( "
+ SELECT order_id
+ FROM {$wpdb->prefix}woocommerce_order_items
+ WHERE order_item_id IN ( SELECT order_item_id FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE meta_key = '_product_id' AND meta_value = %d )
+ AND order_item_type = 'line_item'
+ ", $request['product'] ) );
+
+ // Force WP_Query return empty if don't found any order.
+ $order_ids = ! empty( $order_ids ) ? $order_ids : array( 0 );
+
+ $args['post__in'] = $order_ids;
+ }
+
+ // Search.
+ if ( ! empty( $args['s'] ) ) {
+ $order_ids = wc_order_search( $args['s'] );
+
+ if ( ! empty( $order_ids ) ) {
+ unset( $args['s'] );
+ $args['post__in'] = array_merge( $order_ids, array( 0 ) );
+ }
+ }
+
+ return $args;
+ }
+
+ /**
+ * Prepare a single order output for response.
+ *
+ * @deprecated 3.0
+ *
+ * @param WP_Post $post Post object.
+ * @param WP_REST_Request $request Request object.
+ * @return WP_REST_Response $data
+ */
+ public function prepare_item_for_response( $post, $request ) {
+ $this->request = $request;
+ $this->request['dp'] = is_null( $this->request['dp'] ) ? wc_get_price_decimals() : absint( $this->request['dp'] );
+ $statuses = wc_get_order_statuses();
+ $order = wc_get_order( $post );
+ $data = array_merge( array( 'id' => $order->get_id() ), $order->get_data() );
+ $format_decimal = array( 'discount_total', 'discount_tax', 'shipping_total', 'shipping_tax', 'shipping_total', 'shipping_tax', 'cart_tax', 'total', 'total_tax' );
+ $format_date = array( 'date_created', 'date_modified', 'date_completed', 'date_paid' );
+ $format_line_items = array( 'line_items', 'tax_lines', 'shipping_lines', 'fee_lines', 'coupon_lines' );
+
+ // Format decimal values.
+ foreach ( $format_decimal as $key ) {
+ $data[ $key ] = wc_format_decimal( $data[ $key ], $this->request['dp'] );
+ }
+
+ // Format date values.
+ foreach ( $format_date as $key ) {
+ $data[ $key ] = $data[ $key ] ? wc_rest_prepare_date_response( get_gmt_from_date( date( 'Y-m-d H:i:s', $data[ $key ] ) ) ) : false;
+ }
+
+ // Format the order status.
+ $data['status'] = 'wc-' === substr( $data['status'], 0, 3 ) ? substr( $data['status'], 3 ) : $data['status'];
+
+ // Format line items.
+ foreach ( $format_line_items as $key ) {
+ $data[ $key ] = array_values( array_map( array( $this, 'get_order_item_data' ), $data[ $key ] ) );
+ }
+
+ // Refunds.
+ $data['refunds'] = array();
+ foreach ( $order->get_refunds() as $refund ) {
+ $data['refunds'][] = array(
+ 'id' => $refund->get_id(),
+ 'refund' => $refund->get_reason() ? $refund->get_reason() : '',
+ 'total' => '-' . wc_format_decimal( $refund->get_amount(), $this->request['dp'] ),
+ );
+ }
+
+ $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
+ $data = $this->add_additional_fields_to_object( $data, $request );
+ $data = $this->filter_response_by_context( $data, $context );
+ $response = rest_ensure_response( $data );
+ $response->add_links( $this->prepare_links( $order, $request ) );
+
+ /**
+ * Filter the data for a response.
+ *
+ * The dynamic portion of the hook name, $this->post_type, refers to post_type of the post being
+ * prepared for the response.
+ *
+ * @param WP_REST_Response $response The response object.
+ * @param WP_Post $post Post object.
+ * @param WP_REST_Request $request Request object.
+ */
+ return apply_filters( "woocommerce_rest_prepare_{$this->post_type}", $response, $post, $request );
+ }
+
+ /**
+ * Prepare a single order for create.
+ *
+ * @deprecated 3.0
+ *
+ * @param WP_REST_Request $request Request object.
+ * @return WP_Error|WC_Order $data Object.
+ */
+ protected function prepare_item_for_database( $request ) {
+ $id = isset( $request['id'] ) ? absint( $request['id'] ) : 0;
+ $order = new WC_Order( $id );
+ $schema = $this->get_item_schema();
+ $data_keys = array_keys( array_filter( $schema['properties'], array( $this, 'filter_writable_props' ) ) );
+
+ // Handle all writable props
+ foreach ( $data_keys as $key ) {
+ $value = $request[ $key ];
+
+ if ( ! is_null( $value ) ) {
+ switch ( $key ) {
+ case 'billing' :
+ case 'shipping' :
+ $this->update_address( $order, $value, $key );
+ break;
+ case 'line_items' :
+ case 'shipping_lines' :
+ case 'fee_lines' :
+ case 'coupon_lines' :
+ if ( is_array( $value ) ) {
+ foreach ( $value as $item ) {
+ if ( is_array( $item ) ) {
+ if ( $this->item_is_null( $item ) || ( isset( $item['quantity'] ) && 0 === $item['quantity'] ) ) {
+ $order->remove_item( $item['id'] );
+ } else {
+ $this->set_item( $order, $key, $item );
+ }
+ }
+ }
+ }
+ break;
+ case 'meta_data' :
+ if ( is_array( $value ) ) {
+ foreach ( $value as $meta ) {
+ $order->update_meta_data( $meta['key'], $meta['value'], isset( $meta['id'] ) ? $meta['id'] : '' );
+ }
+ }
+ break;
+ default :
+ if ( is_callable( array( $order, "set_{$key}" ) ) ) {
+ $order->{"set_{$key}"}( $value );
+ }
+ break;
+ }
+ }
+ }
+
+ /**
+ * Filter the data for the insert.
+ *
+ * The dynamic portion of the hook name, $this->post_type, refers to post_type of the post being
+ * prepared for the response.
+ *
+ * @param WC_Order $order The Order object.
+ * @param WP_REST_Request $request Request object.
+ */
+ return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}", $order, $request );
+ }
+
+ /**
+ * Create base WC Order object.
+ *
+ * @deprecated 3.0.0
+ *
+ * @param array $data
+ * @return WC_Order
+ */
+ protected function create_base_order( $data ) {
+ return wc_create_order( $data );
+ }
+
+ /**
+ * Create order.
+ *
+ * @deprecated 3.0.0
+ *
+ * @param WP_REST_Request $request Full details about the request.
+ * @return int|WP_Error
+ */
+ protected function create_order( $request ) {
+ try {
+ // Make sure customer exists.
+ if ( ! is_null( $request['customer_id'] ) && 0 !== $request['customer_id'] && false === get_user_by( 'id', $request['customer_id'] ) ) {
+ throw new WC_REST_Exception( 'woocommerce_rest_invalid_customer_id',__( 'Customer ID is invalid.', 'woocommerce' ), 400 );
+ }
+
+ // Make sure customer is part of blog.
+ if ( is_multisite() && ! is_user_member_of_blog( $request['customer_id'] ) ) {
+ add_user_to_blog( get_current_blog_id(), $request['customer_id'], 'customer' );
+ }
+
+ $order = $this->prepare_item_for_database( $request );
+ $order->set_created_via( 'rest-api' );
+ $order->set_prices_include_tax( 'yes' === get_option( 'woocommerce_prices_include_tax' ) );
+ $order->calculate_totals();
+ $order->save();
+
+ // Handle set paid.
+ if ( true === $request['set_paid'] ) {
+ $order->payment_complete( $request['transaction_id'] );
+ }
+
+ return $order->get_id();
+ } catch ( WC_Data_Exception $e ) {
+ return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() );
+ } catch ( WC_REST_Exception $e ) {
+ return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
+ }
+ }
+
+ /**
+ * Update order.
+ *
+ * @deprecated 3.0.0
+ *
+ * @param WP_REST_Request $request Full details about the request.
+ * @return int|WP_Error
+ */
+ protected function update_order( $request ) {
+ try {
+ $order = $this->prepare_item_for_database( $request );
+ $order->save();
+
+ // Handle set paid.
+ if ( $order->needs_payment() && true === $request['set_paid'] ) {
+ $order->payment_complete( $request['transaction_id'] );
+ }
+
+ // If items have changed, recalculate order totals.
+ if ( isset( $request['billing'] ) || isset( $request['shipping'] ) || isset( $request['line_items'] ) || isset( $request['shipping_lines'] ) || isset( $request['fee_lines'] ) || isset( $request['coupon_lines'] ) ) {
+ $order->calculate_totals();
+ }
+
+ return $order->get_id();
+ } catch ( WC_Data_Exception $e ) {
+ return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() );
+ } catch ( WC_REST_Exception $e ) {
+ return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
+ }
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/class-wc-rest-legacy-products-controller.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/class-wc-rest-legacy-products-controller.php
new file mode 100644
index 0000000..4f7ce18
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/class-wc-rest-legacy-products-controller.php
@@ -0,0 +1,804 @@
+ 'category',
+ 'product_tag' => 'tag',
+ 'product_shipping_class' => 'shipping_class',
+ );
+
+ // Set tax_query for each passed arg.
+ foreach ( $taxonomies as $taxonomy => $key ) {
+ if ( ! empty( $request[ $key ] ) ) {
+ $tax_query[] = array(
+ 'taxonomy' => $taxonomy,
+ 'field' => 'term_id',
+ 'terms' => $request[ $key ],
+ );
+ }
+ }
+
+ // Filter product type by slug.
+ if ( ! empty( $request['type'] ) ) {
+ $tax_query[] = array(
+ 'taxonomy' => 'product_type',
+ 'field' => 'slug',
+ 'terms' => $request['type'],
+ );
+ }
+
+ // Filter by attribute and term.
+ if ( ! empty( $request['attribute'] ) && ! empty( $request['attribute_term'] ) ) {
+ if ( in_array( $request['attribute'], wc_get_attribute_taxonomy_names(), true ) ) {
+ $tax_query[] = array(
+ 'taxonomy' => $request['attribute'],
+ 'field' => 'term_id',
+ 'terms' => $request['attribute_term'],
+ );
+ }
+ }
+
+ if ( ! empty( $tax_query ) ) {
+ $args['tax_query'] = $tax_query;
+ }
+
+ // Filter featured.
+ if ( is_bool( $request['featured'] ) ) {
+ $args['tax_query'][] = array(
+ 'taxonomy' => 'product_visibility',
+ 'field' => 'name',
+ 'terms' => 'featured',
+ 'operator' => true === $request['featured'] ? 'IN' : 'NOT IN',
+ );
+ }
+
+ // Filter by sku.
+ if ( ! empty( $request['sku'] ) ) {
+ $skus = explode( ',', $request['sku'] );
+ // Include the current string as a SKU too.
+ if ( 1 < count( $skus ) ) {
+ $skus[] = $request['sku'];
+ }
+
+ $args['meta_query'] = $this->add_meta_query( $args, array(
+ 'key' => '_sku',
+ 'value' => $skus,
+ 'compare' => 'IN',
+ ) );
+ }
+
+ // Filter by tax class.
+ if ( ! empty( $request['tax_class'] ) ) {
+ $args['meta_query'] = $this->add_meta_query( $args, array(
+ 'key' => '_tax_class',
+ 'value' => 'standard' !== $request['tax_class'] ? $request['tax_class'] : '',
+ ) );
+ }
+
+ // Price filter.
+ if ( ! empty( $request['min_price'] ) || ! empty( $request['max_price'] ) ) {
+ $args['meta_query'] = $this->add_meta_query( $args, wc_get_min_max_price_meta_query( $request ) );
+ }
+
+ // Filter product in stock or out of stock.
+ if ( is_bool( $request['in_stock'] ) ) {
+ $args['meta_query'] = $this->add_meta_query( $args, array(
+ 'key' => '_stock_status',
+ 'value' => true === $request['in_stock'] ? 'instock' : 'outofstock',
+ ) );
+ }
+
+ // Filter by on sale products.
+ if ( is_bool( $request['on_sale'] ) ) {
+ $on_sale_key = $request['on_sale'] ? 'post__in' : 'post__not_in';
+ $args[ $on_sale_key ] += wc_get_product_ids_on_sale();
+ }
+
+ // Force the post_type argument, since it's not a user input variable.
+ if ( ! empty( $request['sku'] ) ) {
+ $args['post_type'] = array( 'product', 'product_variation' );
+ } else {
+ $args['post_type'] = $this->post_type;
+ }
+
+ return $args;
+ }
+
+ /**
+ * Prepare a single product output for response.
+ *
+ * @deprecated 3.0.0
+ *
+ * @param WP_Post $post Post object.
+ * @param WP_REST_Request $request Request object.
+ * @return WP_REST_Response
+ */
+ public function prepare_item_for_response( $post, $request ) {
+ $product = wc_get_product( $post );
+ $data = $this->get_product_data( $product );
+
+ // Add variations to variable products.
+ if ( $product->is_type( 'variable' ) && $product->has_child() ) {
+ $data['variations'] = $product->get_children();
+ }
+
+ // Add grouped products data.
+ if ( $product->is_type( 'grouped' ) && $product->has_child() ) {
+ $data['grouped_products'] = $product->get_children();
+ }
+
+ $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
+ $data = $this->add_additional_fields_to_object( $data, $request );
+ $data = $this->filter_response_by_context( $data, $context );
+
+ // Wrap the data in a response object.
+ $response = rest_ensure_response( $data );
+
+ $response->add_links( $this->prepare_links( $product, $request ) );
+
+ /**
+ * Filter the data for a response.
+ *
+ * The dynamic portion of the hook name, $this->post_type, refers to post_type of the post being
+ * prepared for the response.
+ *
+ * @param WP_REST_Response $response The response object.
+ * @param WP_Post $post Post object.
+ * @param WP_REST_Request $request Request object.
+ */
+ return apply_filters( "woocommerce_rest_prepare_{$this->post_type}", $response, $post, $request );
+ }
+
+ /**
+ * Get product menu order.
+ *
+ * @deprecated 3.0.0
+ * @param WC_Product $product Product instance.
+ * @return int
+ */
+ protected function get_product_menu_order( $product ) {
+ return $product->get_menu_order();
+ }
+
+ /**
+ * Save product meta.
+ *
+ * @deprecated 3.0.0
+ * @param WC_Product $product
+ * @param WP_REST_Request $request
+ * @return bool
+ * @throws WC_REST_Exception
+ */
+ protected function save_product_meta( $product, $request ) {
+ $product = $this->set_product_meta( $product, $request );
+ $product->save();
+
+ return true;
+ }
+
+ /**
+ * Set product meta.
+ *
+ * @deprecated 3.0.0
+ *
+ * @throws WC_REST_Exception REST API exceptions.
+ * @param WC_Product $product Product instance.
+ * @param WP_REST_Request $request Request data.
+ * @return WC_Product
+ */
+ protected function set_product_meta( $product, $request ) {
+ // Virtual.
+ if ( isset( $request['virtual'] ) ) {
+ $product->set_virtual( $request['virtual'] );
+ }
+
+ // Tax status.
+ if ( isset( $request['tax_status'] ) ) {
+ $product->set_tax_status( $request['tax_status'] );
+ }
+
+ // Tax Class.
+ if ( isset( $request['tax_class'] ) ) {
+ $product->set_tax_class( $request['tax_class'] );
+ }
+
+ // Catalog Visibility.
+ if ( isset( $request['catalog_visibility'] ) ) {
+ $product->set_catalog_visibility( $request['catalog_visibility'] );
+ }
+
+ // Purchase Note.
+ if ( isset( $request['purchase_note'] ) ) {
+ $product->set_purchase_note( wc_clean( $request['purchase_note'] ) );
+ }
+
+ // Featured Product.
+ if ( isset( $request['featured'] ) ) {
+ $product->set_featured( $request['featured'] );
+ }
+
+ // Shipping data.
+ $product = $this->save_product_shipping_data( $product, $request );
+
+ // SKU.
+ if ( isset( $request['sku'] ) ) {
+ $product->set_sku( wc_clean( $request['sku'] ) );
+ }
+
+ // Attributes.
+ if ( isset( $request['attributes'] ) ) {
+ $attributes = array();
+
+ foreach ( $request['attributes'] as $attribute ) {
+ $attribute_id = 0;
+ $attribute_name = '';
+
+ // Check ID for global attributes or name for product attributes.
+ if ( ! empty( $attribute['id'] ) ) {
+ $attribute_id = absint( $attribute['id'] );
+ $attribute_name = wc_attribute_taxonomy_name_by_id( $attribute_id );
+ } elseif ( ! empty( $attribute['name'] ) ) {
+ $attribute_name = wc_clean( $attribute['name'] );
+ }
+
+ if ( ! $attribute_id && ! $attribute_name ) {
+ continue;
+ }
+
+ if ( $attribute_id ) {
+
+ if ( isset( $attribute['options'] ) ) {
+ $options = $attribute['options'];
+
+ if ( ! is_array( $attribute['options'] ) ) {
+ // Text based attributes - Posted values are term names.
+ $options = explode( WC_DELIMITER, $options );
+ }
+
+ $values = array_map( 'wc_sanitize_term_text_based', $options );
+ $values = array_filter( $values, 'strlen' );
+ } else {
+ $values = array();
+ }
+
+ if ( ! empty( $values ) ) {
+ // Add attribute to array, but don't set values.
+ $attribute_object = new WC_Product_Attribute();
+ $attribute_object->set_id( $attribute_id );
+ $attribute_object->set_name( $attribute_name );
+ $attribute_object->set_options( $values );
+ $attribute_object->set_position( isset( $attribute['position'] ) ? (string) absint( $attribute['position'] ) : '0' );
+ $attribute_object->set_visible( ( isset( $attribute['visible'] ) && $attribute['visible'] ) ? 1 : 0 );
+ $attribute_object->set_variation( ( isset( $attribute['variation'] ) && $attribute['variation'] ) ? 1 : 0 );
+ $attributes[] = $attribute_object;
+ }
+ } elseif ( isset( $attribute['options'] ) ) {
+ // Custom attribute - Add attribute to array and set the values.
+ if ( is_array( $attribute['options'] ) ) {
+ $values = $attribute['options'];
+ } else {
+ $values = explode( WC_DELIMITER, $attribute['options'] );
+ }
+ $attribute_object = new WC_Product_Attribute();
+ $attribute_object->set_name( $attribute_name );
+ $attribute_object->set_options( $values );
+ $attribute_object->set_position( isset( $attribute['position'] ) ? (string) absint( $attribute['position'] ) : '0' );
+ $attribute_object->set_visible( ( isset( $attribute['visible'] ) && $attribute['visible'] ) ? 1 : 0 );
+ $attribute_object->set_variation( ( isset( $attribute['variation'] ) && $attribute['variation'] ) ? 1 : 0 );
+ $attributes[] = $attribute_object;
+ }
+ }
+ $product->set_attributes( $attributes );
+ }
+
+ // Sales and prices.
+ if ( in_array( $product->get_type(), array( 'variable', 'grouped' ), true ) ) {
+ $product->set_regular_price( '' );
+ $product->set_sale_price( '' );
+ $product->set_date_on_sale_to( '' );
+ $product->set_date_on_sale_from( '' );
+ $product->set_price( '' );
+ } else {
+ // Regular Price.
+ if ( isset( $request['regular_price'] ) ) {
+ $product->set_regular_price( $request['regular_price'] );
+ }
+
+ // Sale Price.
+ if ( isset( $request['sale_price'] ) ) {
+ $product->set_sale_price( $request['sale_price'] );
+ }
+
+ if ( isset( $request['date_on_sale_from'] ) ) {
+ $product->set_date_on_sale_from( $request['date_on_sale_from'] );
+ }
+
+ if ( isset( $request['date_on_sale_to'] ) ) {
+ $product->set_date_on_sale_to( $request['date_on_sale_to'] );
+ }
+ }
+
+ // Product parent ID for groups.
+ if ( isset( $request['parent_id'] ) ) {
+ $product->set_parent_id( $request['parent_id'] );
+ }
+
+ // Sold individually.
+ if ( isset( $request['sold_individually'] ) ) {
+ $product->set_sold_individually( $request['sold_individually'] );
+ }
+
+ // Stock status.
+ if ( isset( $request['in_stock'] ) ) {
+ $stock_status = true === $request['in_stock'] ? 'instock' : 'outofstock';
+ } else {
+ $stock_status = $product->get_stock_status();
+ }
+
+ // Stock data.
+ if ( 'yes' === get_option( 'woocommerce_manage_stock' ) ) {
+ // Manage stock.
+ if ( isset( $request['manage_stock'] ) ) {
+ $product->set_manage_stock( $request['manage_stock'] );
+ }
+
+ // Backorders.
+ if ( isset( $request['backorders'] ) ) {
+ $product->set_backorders( $request['backorders'] );
+ }
+
+ if ( $product->is_type( 'grouped' ) ) {
+ $product->set_manage_stock( 'no' );
+ $product->set_backorders( 'no' );
+ $product->set_stock_quantity( '' );
+ $product->set_stock_status( $stock_status );
+ } elseif ( $product->is_type( 'external' ) ) {
+ $product->set_manage_stock( 'no' );
+ $product->set_backorders( 'no' );
+ $product->set_stock_quantity( '' );
+ $product->set_stock_status( 'instock' );
+ } elseif ( $product->get_manage_stock() ) {
+ // Stock status is always determined by children so sync later.
+ if ( ! $product->is_type( 'variable' ) ) {
+ $product->set_stock_status( $stock_status );
+ }
+
+ // Stock quantity.
+ if ( isset( $request['stock_quantity'] ) ) {
+ $product->set_stock_quantity( wc_stock_amount( $request['stock_quantity'] ) );
+ } elseif ( isset( $request['inventory_delta'] ) ) {
+ $stock_quantity = wc_stock_amount( $product->get_stock_quantity() );
+ $stock_quantity += wc_stock_amount( $request['inventory_delta'] );
+ $product->set_stock_quantity( wc_stock_amount( $stock_quantity ) );
+ }
+ } else {
+ // Don't manage stock.
+ $product->set_manage_stock( 'no' );
+ $product->set_stock_quantity( '' );
+ $product->set_stock_status( $stock_status );
+ }
+ } elseif ( ! $product->is_type( 'variable' ) ) {
+ $product->set_stock_status( $stock_status );
+ }
+
+ // Upsells.
+ if ( isset( $request['upsell_ids'] ) ) {
+ $upsells = array();
+ $ids = $request['upsell_ids'];
+
+ if ( ! empty( $ids ) ) {
+ foreach ( $ids as $id ) {
+ if ( $id && $id > 0 ) {
+ $upsells[] = $id;
+ }
+ }
+ }
+
+ $product->set_upsell_ids( $upsells );
+ }
+
+ // Cross sells.
+ if ( isset( $request['cross_sell_ids'] ) ) {
+ $crosssells = array();
+ $ids = $request['cross_sell_ids'];
+
+ if ( ! empty( $ids ) ) {
+ foreach ( $ids as $id ) {
+ if ( $id && $id > 0 ) {
+ $crosssells[] = $id;
+ }
+ }
+ }
+
+ $product->set_cross_sell_ids( $crosssells );
+ }
+
+ // Product categories.
+ if ( isset( $request['categories'] ) && is_array( $request['categories'] ) ) {
+ $product = $this->save_taxonomy_terms( $product, $request['categories'] );
+ }
+
+ // Product tags.
+ if ( isset( $request['tags'] ) && is_array( $request['tags'] ) ) {
+ $product = $this->save_taxonomy_terms( $product, $request['tags'], 'tag' );
+ }
+
+ // Downloadable.
+ if ( isset( $request['downloadable'] ) ) {
+ $product->set_downloadable( $request['downloadable'] );
+ }
+
+ // Downloadable options.
+ if ( $product->get_downloadable() ) {
+
+ // Downloadable files.
+ if ( isset( $request['downloads'] ) && is_array( $request['downloads'] ) ) {
+ $product = $this->save_downloadable_files( $product, $request['downloads'] );
+ }
+
+ // Download limit.
+ if ( isset( $request['download_limit'] ) ) {
+ $product->set_download_limit( $request['download_limit'] );
+ }
+
+ // Download expiry.
+ if ( isset( $request['download_expiry'] ) ) {
+ $product->set_download_expiry( $request['download_expiry'] );
+ }
+ }
+
+ // Product url and button text for external products.
+ if ( $product->is_type( 'external' ) ) {
+ if ( isset( $request['external_url'] ) ) {
+ $product->set_product_url( $request['external_url'] );
+ }
+
+ if ( isset( $request['button_text'] ) ) {
+ $product->set_button_text( $request['button_text'] );
+ }
+ }
+
+ // Save default attributes for variable products.
+ if ( $product->is_type( 'variable' ) ) {
+ $product = $this->save_default_attributes( $product, $request );
+ }
+
+ return $product;
+ }
+
+ /**
+ * Save variations.
+ *
+ * @deprecated 3.0.0
+ *
+ * @throws WC_REST_Exception REST API exceptions.
+ * @param WC_Product $product Product instance.
+ * @param WP_REST_Request $request Request data.
+ * @return bool
+ */
+ protected function save_variations_data( $product, $request ) {
+ foreach ( $request['variations'] as $menu_order => $data ) {
+ $variation = new WC_Product_Variation( isset( $data['id'] ) ? absint( $data['id'] ) : 0 );
+
+ // Create initial name and status.
+ if ( ! $variation->get_slug() ) {
+ /* translators: 1: variation id 2: product name */
+ $variation->set_name( sprintf( __( 'Variation #%1$s of %2$s', 'woocommerce' ), $variation->get_id(), $product->get_name() ) );
+ $variation->set_status( isset( $data['visible'] ) && false === $data['visible'] ? 'private' : 'publish' );
+ }
+
+ // Parent ID.
+ $variation->set_parent_id( $product->get_id() );
+
+ // Menu order.
+ $variation->set_menu_order( $menu_order );
+
+ // Status.
+ if ( isset( $data['visible'] ) ) {
+ $variation->set_status( false === $data['visible'] ? 'private' : 'publish' );
+ }
+
+ // SKU.
+ if ( isset( $data['sku'] ) ) {
+ $variation->set_sku( wc_clean( $data['sku'] ) );
+ }
+
+ // Thumbnail.
+ if ( isset( $data['image'] ) && is_array( $data['image'] ) ) {
+ $image = $data['image'];
+ $image = current( $image );
+ if ( is_array( $image ) ) {
+ $image['position'] = 0;
+ }
+
+ $variation = $this->set_product_images( $variation, array( $image ) );
+ }
+
+ // Virtual variation.
+ if ( isset( $data['virtual'] ) ) {
+ $variation->set_virtual( $data['virtual'] );
+ }
+
+ // Downloadable variation.
+ if ( isset( $data['downloadable'] ) ) {
+ $variation->set_downloadable( $data['downloadable'] );
+ }
+
+ // Downloads.
+ if ( $variation->get_downloadable() ) {
+ // Downloadable files.
+ if ( isset( $data['downloads'] ) && is_array( $data['downloads'] ) ) {
+ $variation = $this->save_downloadable_files( $variation, $data['downloads'] );
+ }
+
+ // Download limit.
+ if ( isset( $data['download_limit'] ) ) {
+ $variation->set_download_limit( $data['download_limit'] );
+ }
+
+ // Download expiry.
+ if ( isset( $data['download_expiry'] ) ) {
+ $variation->set_download_expiry( $data['download_expiry'] );
+ }
+ }
+
+ // Shipping data.
+ $variation = $this->save_product_shipping_data( $variation, $data );
+
+ // Stock handling.
+ if ( isset( $data['manage_stock'] ) ) {
+ $variation->set_manage_stock( $data['manage_stock'] );
+ }
+
+ if ( isset( $data['in_stock'] ) ) {
+ $variation->set_stock_status( true === $data['in_stock'] ? 'instock' : 'outofstock' );
+ }
+
+ if ( isset( $data['backorders'] ) ) {
+ $variation->set_backorders( $data['backorders'] );
+ }
+
+ if ( $variation->get_manage_stock() ) {
+ if ( isset( $data['stock_quantity'] ) ) {
+ $variation->set_stock_quantity( $data['stock_quantity'] );
+ } elseif ( isset( $data['inventory_delta'] ) ) {
+ $stock_quantity = wc_stock_amount( $variation->get_stock_quantity() );
+ $stock_quantity += wc_stock_amount( $data['inventory_delta'] );
+ $variation->set_stock_quantity( $stock_quantity );
+ }
+ } else {
+ $variation->set_backorders( 'no' );
+ $variation->set_stock_quantity( '' );
+ }
+
+ // Regular Price.
+ if ( isset( $data['regular_price'] ) ) {
+ $variation->set_regular_price( $data['regular_price'] );
+ }
+
+ // Sale Price.
+ if ( isset( $data['sale_price'] ) ) {
+ $variation->set_sale_price( $data['sale_price'] );
+ }
+
+ if ( isset( $data['date_on_sale_from'] ) ) {
+ $variation->set_date_on_sale_from( $data['date_on_sale_from'] );
+ }
+
+ if ( isset( $data['date_on_sale_to'] ) ) {
+ $variation->set_date_on_sale_to( $data['date_on_sale_to'] );
+ }
+
+ // Tax class.
+ if ( isset( $data['tax_class'] ) ) {
+ $variation->set_tax_class( $data['tax_class'] );
+ }
+
+ // Description.
+ if ( isset( $data['description'] ) ) {
+ $variation->set_description( wp_kses_post( $data['description'] ) );
+ }
+
+ // Update taxonomies.
+ if ( isset( $data['attributes'] ) ) {
+ $attributes = array();
+ $parent_attributes = $product->get_attributes();
+
+ foreach ( $data['attributes'] as $attribute ) {
+ $attribute_id = 0;
+ $attribute_name = '';
+
+ // Check ID for global attributes or name for product attributes.
+ if ( ! empty( $attribute['id'] ) ) {
+ $attribute_id = absint( $attribute['id'] );
+ $attribute_name = wc_attribute_taxonomy_name_by_id( $attribute_id );
+ } elseif ( ! empty( $attribute['name'] ) ) {
+ $attribute_name = sanitize_title( $attribute['name'] );
+ }
+
+ if ( ! $attribute_id && ! $attribute_name ) {
+ continue;
+ }
+
+ if ( ! isset( $parent_attributes[ $attribute_name ] ) || ! $parent_attributes[ $attribute_name ]->get_variation() ) {
+ continue;
+ }
+
+ $attribute_key = sanitize_title( $parent_attributes[ $attribute_name ]->get_name() );
+ $attribute_value = isset( $attribute['option'] ) ? wc_clean( stripslashes( $attribute['option'] ) ) : '';
+
+ if ( $parent_attributes[ $attribute_name ]->is_taxonomy() ) {
+ // If dealing with a taxonomy, we need to get the slug from the name posted to the API.
+ $term = get_term_by( 'name', $attribute_value, $attribute_name );
+
+ if ( $term && ! is_wp_error( $term ) ) {
+ $attribute_value = $term->slug;
+ } else {
+ $attribute_value = sanitize_title( $attribute_value );
+ }
+ }
+
+ $attributes[ $attribute_key ] = $attribute_value;
+ }
+
+ $variation->set_attributes( $attributes );
+ }
+
+ $variation->save();
+
+ do_action( 'woocommerce_rest_save_product_variation', $variation->get_id(), $menu_order, $data );
+ }
+
+ return true;
+ }
+
+ /**
+ * Add post meta fields.
+ *
+ * @deprecated 3.0.0
+ *
+ * @param WP_Post $post Post data.
+ * @param WP_REST_Request $request Request data.
+ * @return bool|WP_Error
+ */
+ protected function add_post_meta_fields( $post, $request ) {
+ return $this->update_post_meta_fields( $post, $request );
+ }
+
+ /**
+ * Update post meta fields.
+ *
+ * @param WP_Post $post Post data.
+ * @param WP_REST_Request $request Request data.
+ * @return bool|WP_Error
+ */
+ protected function update_post_meta_fields( $post, $request ) {
+ $product = wc_get_product( $post );
+
+ // Check for featured/gallery images, upload it and set it.
+ if ( isset( $request['images'] ) ) {
+ $product = $this->set_product_images( $product, $request['images'] );
+ }
+
+ // Save product meta fields.
+ $product = $this->set_product_meta( $product, $request );
+
+ // Save the product data.
+ $product->save();
+
+ // Save variations.
+ if ( $product->is_type( 'variable' ) ) {
+ if ( isset( $request['variations'] ) && is_array( $request['variations'] ) ) {
+ $this->save_variations_data( $product, $request );
+ }
+ }
+
+ // Clear caches here so in sync with any new variations/children.
+ wc_delete_product_transients( $product->get_id() );
+ wp_cache_delete( 'product-' . $product->get_id(), 'products' );
+
+ return true;
+ }
+
+ /**
+ * Delete post.
+ *
+ * @deprecated 3.0.0
+ *
+ * @param int|WP_Post $id Post ID or WP_Post instance.
+ */
+ protected function delete_post( $id ) {
+ if ( ! empty( $id->ID ) ) {
+ $id = $id->ID;
+ } elseif ( ! is_numeric( $id ) || 0 >= $id ) {
+ return;
+ }
+
+ // Delete product attachments.
+ $attachments = get_posts( array(
+ 'post_parent' => $id,
+ 'post_status' => 'any',
+ 'post_type' => 'attachment',
+ ) );
+
+ foreach ( (array) $attachments as $attachment ) {
+ wp_delete_attachment( $attachment->ID, true );
+ }
+
+ // Delete product.
+ $product = wc_get_product( $id );
+ $product->delete( true );
+ }
+
+ /**
+ * Get post types.
+ *
+ * @deprecated 3.0.0
+ *
+ * @return array
+ */
+ protected function get_post_types() {
+ return array( 'product', 'product_variation' );
+ }
+
+ /**
+ * Save product images.
+ *
+ * @deprecated 3.0.0
+ *
+ * @param int $product_id
+ * @param array $images
+ * @throws WC_REST_Exception
+ */
+ protected function save_product_images( $product_id, $images ) {
+ $product = wc_get_product( $product_id );
+
+ return set_product_images( $product, $images );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/v1/class-wc-api-authentication.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/v1/class-wc-api-authentication.php
new file mode 100644
index 0000000..b80b26b
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/v1/class-wc-api-authentication.php
@@ -0,0 +1,410 @@
+api->server->path ) {
+ return new WP_User( 0 );
+ }
+
+ try {
+
+ if ( is_ssl() ) {
+ $keys = $this->perform_ssl_authentication();
+ } else {
+ $keys = $this->perform_oauth_authentication();
+ }
+
+ // Check API key-specific permission
+ $this->check_api_key_permissions( $keys['permissions'] );
+
+ $user = $this->get_user_by_id( $keys['user_id'] );
+
+ $this->update_api_key_last_access( $keys['key_id'] );
+
+ } catch ( Exception $e ) {
+ $user = new WP_Error( 'woocommerce_api_authentication_error', $e->getMessage(), array( 'status' => $e->getCode() ) );
+ }
+
+ return $user;
+ }
+
+ /**
+ * SSL-encrypted requests are not subject to sniffing or man-in-the-middle
+ * attacks, so the request can be authenticated by simply looking up the user
+ * associated with the given consumer key and confirming the consumer secret
+ * provided is valid
+ *
+ * @since 2.1
+ * @return array
+ * @throws Exception
+ */
+ private function perform_ssl_authentication() {
+
+ $params = WC()->api->server->params['GET'];
+
+ // Get consumer key
+ if ( ! empty( $_SERVER['PHP_AUTH_USER'] ) ) {
+
+ // Should be in HTTP Auth header by default
+ $consumer_key = $_SERVER['PHP_AUTH_USER'];
+
+ } elseif ( ! empty( $params['consumer_key'] ) ) {
+
+ // Allow a query string parameter as a fallback
+ $consumer_key = $params['consumer_key'];
+
+ } else {
+
+ throw new Exception( __( 'Consumer key is missing.', 'woocommerce' ), 404 );
+ }
+
+ // Get consumer secret
+ if ( ! empty( $_SERVER['PHP_AUTH_PW'] ) ) {
+
+ // Should be in HTTP Auth header by default
+ $consumer_secret = $_SERVER['PHP_AUTH_PW'];
+
+ } elseif ( ! empty( $params['consumer_secret'] ) ) {
+
+ // Allow a query string parameter as a fallback
+ $consumer_secret = $params['consumer_secret'];
+
+ } else {
+
+ throw new Exception( __( 'Consumer secret is missing.', 'woocommerce' ), 404 );
+ }
+
+ $keys = $this->get_keys_by_consumer_key( $consumer_key );
+
+ if ( ! $this->is_consumer_secret_valid( $keys['consumer_secret'], $consumer_secret ) ) {
+ throw new Exception( __( 'Consumer secret is invalid.', 'woocommerce' ), 401 );
+ }
+
+ return $keys;
+ }
+
+ /**
+ * Perform OAuth 1.0a "one-legged" (http://oauthbible.com/#oauth-10a-one-legged) authentication for non-SSL requests
+ *
+ * This is required so API credentials cannot be sniffed or intercepted when making API requests over plain HTTP
+ *
+ * This follows the spec for simple OAuth 1.0a authentication (RFC 5849) as closely as possible, with two exceptions:
+ *
+ * 1) There is no token associated with request/responses, only consumer keys/secrets are used
+ *
+ * 2) The OAuth parameters are included as part of the request query string instead of part of the Authorization header,
+ * This is because there is no cross-OS function within PHP to get the raw Authorization header
+ *
+ * @link http://tools.ietf.org/html/rfc5849 for the full spec
+ * @since 2.1
+ * @return array
+ * @throws Exception
+ */
+ private function perform_oauth_authentication() {
+
+ $params = WC()->api->server->params['GET'];
+
+ $param_names = array( 'oauth_consumer_key', 'oauth_timestamp', 'oauth_nonce', 'oauth_signature', 'oauth_signature_method' );
+
+ // Check for required OAuth parameters
+ foreach ( $param_names as $param_name ) {
+
+ if ( empty( $params[ $param_name ] ) ) {
+ /* translators: %s: parameter name */
+ throw new Exception( sprintf( __( '%s parameter is missing', 'woocommerce' ), $param_name ), 404 );
+ }
+ }
+
+ // Fetch WP user by consumer key
+ $keys = $this->get_keys_by_consumer_key( $params['oauth_consumer_key'] );
+
+ // Perform OAuth validation
+ $this->check_oauth_signature( $keys, $params );
+ $this->check_oauth_timestamp_and_nonce( $keys, $params['oauth_timestamp'], $params['oauth_nonce'] );
+
+ // Authentication successful, return user
+ return $keys;
+ }
+
+ /**
+ * Return the keys for the given consumer key
+ *
+ * @since 2.4.0
+ * @param string $consumer_key
+ * @return array
+ * @throws Exception
+ */
+ private function get_keys_by_consumer_key( $consumer_key ) {
+ global $wpdb;
+
+ $consumer_key = wc_api_hash( sanitize_text_field( $consumer_key ) );
+
+ $keys = $wpdb->get_row( $wpdb->prepare( "
+ SELECT key_id, user_id, permissions, consumer_key, consumer_secret, nonces
+ FROM {$wpdb->prefix}woocommerce_api_keys
+ WHERE consumer_key = '%s'
+ ", $consumer_key ), ARRAY_A );
+
+ if ( empty( $keys ) ) {
+ throw new Exception( __( 'Consumer key is invalid.', 'woocommerce' ), 401 );
+ }
+
+ return $keys;
+ }
+
+ /**
+ * Get user by ID
+ *
+ * @since 2.4.0
+ * @param int $user_id
+ * @return WP_User
+ *
+ * @throws Exception
+ */
+ private function get_user_by_id( $user_id ) {
+ $user = get_user_by( 'id', $user_id );
+
+ if ( ! $user ) {
+ throw new Exception( __( 'API user is invalid', 'woocommerce' ), 401 );
+ }
+
+ return $user;
+ }
+
+ /**
+ * Check if the consumer secret provided for the given user is valid
+ *
+ * @since 2.1
+ * @param string $keys_consumer_secret
+ * @param string $consumer_secret
+ * @return bool
+ */
+ private function is_consumer_secret_valid( $keys_consumer_secret, $consumer_secret ) {
+ return hash_equals( $keys_consumer_secret, $consumer_secret );
+ }
+
+ /**
+ * Verify that the consumer-provided request signature matches our generated signature, this ensures the consumer
+ * has a valid key/secret
+ *
+ * @param array $keys
+ * @param array $params the request parameters
+ * @throws Exception
+ */
+ private function check_oauth_signature( $keys, $params ) {
+
+ $http_method = strtoupper( WC()->api->server->method );
+
+ $base_request_uri = rawurlencode( untrailingslashit( get_woocommerce_api_url( '' ) ) . WC()->api->server->path );
+
+ // Get the signature provided by the consumer and remove it from the parameters prior to checking the signature
+ $consumer_signature = rawurldecode( str_replace( ' ', '+', $params['oauth_signature'] ) );
+ unset( $params['oauth_signature'] );
+
+ // Remove filters and convert them from array to strings to void normalize issues
+ if ( isset( $params['filter'] ) ) {
+ $filters = $params['filter'];
+ unset( $params['filter'] );
+ foreach ( $filters as $filter => $filter_value ) {
+ $params[ 'filter[' . $filter . ']' ] = $filter_value;
+ }
+ }
+
+ // Normalize parameter key/values
+ $params = $this->normalize_parameters( $params );
+
+ // Sort parameters
+ if ( ! uksort( $params, 'strcmp' ) ) {
+ throw new Exception( __( 'Invalid signature - failed to sort parameters.', 'woocommerce' ), 401 );
+ }
+
+ // Form query string
+ $query_params = array();
+ foreach ( $params as $param_key => $param_value ) {
+
+ $query_params[] = $param_key . '%3D' . $param_value; // join with equals sign
+ }
+ $query_string = implode( '%26', $query_params ); // join with ampersand
+
+ $string_to_sign = $http_method . '&' . $base_request_uri . '&' . $query_string;
+
+ if ( 'HMAC-SHA1' !== $params['oauth_signature_method'] && 'HMAC-SHA256' !== $params['oauth_signature_method'] ) {
+ throw new Exception( __( 'Invalid signature - signature method is invalid.', 'woocommerce' ), 401 );
+ }
+
+ $hash_algorithm = strtolower( str_replace( 'HMAC-', '', $params['oauth_signature_method'] ) );
+
+ $signature = base64_encode( hash_hmac( $hash_algorithm, $string_to_sign, $keys['consumer_secret'], true ) );
+
+ if ( ! hash_equals( $signature, $consumer_signature ) ) {
+ throw new Exception( __( 'Invalid signature - provided signature does not match.', 'woocommerce' ), 401 );
+ }
+ }
+
+ /**
+ * Normalize each parameter by assuming each parameter may have already been
+ * encoded, so attempt to decode, and then re-encode according to RFC 3986
+ *
+ * Note both the key and value is normalized so a filter param like:
+ *
+ * 'filter[period]' => 'week'
+ *
+ * is encoded to:
+ *
+ * 'filter%5Bperiod%5D' => 'week'
+ *
+ * This conforms to the OAuth 1.0a spec which indicates the entire query string
+ * should be URL encoded
+ *
+ * @since 2.1
+ * @see rawurlencode()
+ * @param array $parameters un-normalized parameters
+ * @return array normalized parameters
+ */
+ private function normalize_parameters( $parameters ) {
+
+ $normalized_parameters = array();
+
+ foreach ( $parameters as $key => $value ) {
+
+ // Percent symbols (%) must be double-encoded
+ $key = str_replace( '%', '%25', rawurlencode( rawurldecode( $key ) ) );
+ $value = str_replace( '%', '%25', rawurlencode( rawurldecode( $value ) ) );
+
+ $normalized_parameters[ $key ] = $value;
+ }
+
+ return $normalized_parameters;
+ }
+
+ /**
+ * Verify that the timestamp and nonce provided with the request are valid. This prevents replay attacks where
+ * an attacker could attempt to re-send an intercepted request at a later time.
+ *
+ * - A timestamp is valid if it is within 15 minutes of now
+ * - A nonce is valid if it has not been used within the last 15 minutes
+ *
+ * @param array $keys
+ * @param int $timestamp the unix timestamp for when the request was made
+ * @param string $nonce a unique (for the given user) 32 alphanumeric string, consumer-generated
+ * @throws Exception
+ */
+ private function check_oauth_timestamp_and_nonce( $keys, $timestamp, $nonce ) {
+ global $wpdb;
+
+ $valid_window = 15 * 60; // 15 minute window
+
+ if ( ( $timestamp < time() - $valid_window ) || ( $timestamp > time() + $valid_window ) ) {
+ throw new Exception( __( 'Invalid timestamp.', 'woocommerce' ) );
+ }
+
+ $used_nonces = maybe_unserialize( $keys['nonces'] );
+
+ if ( empty( $used_nonces ) ) {
+ $used_nonces = array();
+ }
+
+ if ( in_array( $nonce, $used_nonces ) ) {
+ throw new Exception( __( 'Invalid nonce - nonce has already been used.', 'woocommerce' ), 401 );
+ }
+
+ $used_nonces[ $timestamp ] = $nonce;
+
+ // Remove expired nonces
+ foreach ( $used_nonces as $nonce_timestamp => $nonce ) {
+ if ( $nonce_timestamp < ( time() - $valid_window ) ) {
+ unset( $used_nonces[ $nonce_timestamp ] );
+ }
+ }
+
+ $used_nonces = maybe_serialize( $used_nonces );
+
+ $wpdb->update(
+ $wpdb->prefix . 'woocommerce_api_keys',
+ array( 'nonces' => $used_nonces ),
+ array( 'key_id' => $keys['key_id'] ),
+ array( '%s' ),
+ array( '%d' )
+ );
+ }
+
+ /**
+ * Check that the API keys provided have the proper key-specific permissions to either read or write API resources
+ *
+ * @param string $key_permissions
+ * @throws Exception if the permission check fails
+ */
+ public function check_api_key_permissions( $key_permissions ) {
+ switch ( WC()->api->server->method ) {
+
+ case 'HEAD':
+ case 'GET':
+ if ( 'read' !== $key_permissions && 'read_write' !== $key_permissions ) {
+ throw new Exception( __( 'The API key provided does not have read permissions.', 'woocommerce' ), 401 );
+ }
+ break;
+
+ case 'POST':
+ case 'PUT':
+ case 'PATCH':
+ case 'DELETE':
+ if ( 'write' !== $key_permissions && 'read_write' !== $key_permissions ) {
+ throw new Exception( __( 'The API key provided does not have write permissions.', 'woocommerce' ), 401 );
+ }
+ break;
+ }
+ }
+
+ /**
+ * Updated API Key last access datetime
+ *
+ * @since 2.4.0
+ *
+ * @param int $key_id
+ */
+ private function update_api_key_last_access( $key_id ) {
+ global $wpdb;
+
+ $wpdb->update(
+ $wpdb->prefix . 'woocommerce_api_keys',
+ array( 'last_access' => current_time( 'mysql' ) ),
+ array( 'key_id' => $key_id ),
+ array( '%s' ),
+ array( '%d' )
+ );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/v1/class-wc-api-coupons.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/v1/class-wc-api-coupons.php
new file mode 100644
index 0000000..49036c6
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/v1/class-wc-api-coupons.php
@@ -0,0 +1,247 @@
+
+ *
+ * @since 2.1
+ * @param array $routes
+ * @return array
+ */
+ public function register_routes( $routes ) {
+
+ # GET /coupons
+ $routes[ $this->base ] = array(
+ array( array( $this, 'get_coupons' ), WC_API_Server::READABLE ),
+ );
+
+ # GET /coupons/count
+ $routes[ $this->base . '/count' ] = array(
+ array( array( $this, 'get_coupons_count' ), WC_API_Server::READABLE ),
+ );
+
+ # GET /coupons/, note that coupon codes can contain spaces, dashes and underscores
+ $routes[ $this->base . '/code/(?P
\w[\w\s\-]*)' ] = array(
+ array( array( $this, 'get_coupon_by_code' ), WC_API_Server::READABLE ),
+ );
+
+ return $routes;
+ }
+
+ /**
+ * Get all coupons
+ *
+ * @since 2.1
+ * @param string $fields
+ * @param array $filter
+ * @param int $page
+ * @return array
+ */
+ public function get_coupons( $fields = null, $filter = array(), $page = 1 ) {
+
+ $filter['page'] = $page;
+
+ $query = $this->query_coupons( $filter );
+
+ $coupons = array();
+
+ foreach ( $query->posts as $coupon_id ) {
+
+ if ( ! $this->is_readable( $coupon_id ) ) {
+ continue;
+ }
+
+ $coupons[] = current( $this->get_coupon( $coupon_id, $fields ) );
+ }
+
+ $this->server->add_pagination_headers( $query );
+
+ return array( 'coupons' => $coupons );
+ }
+
+ /**
+ * Get the coupon for the given ID
+ *
+ * @since 2.1
+ *
+ * @param int $id the coupon ID
+ * @param string $fields fields to include in response
+ *
+ * @return array|WP_Error
+ * @throws WC_API_Exception
+ */
+ public function get_coupon( $id, $fields = null ) {
+ $id = $this->validate_request( $id, 'shop_coupon', 'read' );
+
+ if ( is_wp_error( $id ) ) {
+ return $id;
+ }
+
+ $coupon = new WC_Coupon( $id );
+
+ if ( 0 === $coupon->get_id() ) {
+ throw new WC_API_Exception( 'woocommerce_api_invalid_coupon_id', __( 'Invalid coupon ID', 'woocommerce' ), 404 );
+ }
+
+ $coupon_data = array(
+ 'id' => $coupon->get_id(),
+ 'code' => $coupon->get_code(),
+ 'type' => $coupon->get_discount_type(),
+ 'created_at' => $this->server->format_datetime( $coupon->get_date_created() ? $coupon->get_date_created()->getTimestamp() : 0 ), // API gives UTC times.
+ 'updated_at' => $this->server->format_datetime( $coupon->get_date_modified() ? $coupon->get_date_modified()->getTimestamp() : 0 ), // API gives UTC times.
+ 'amount' => wc_format_decimal( $coupon->get_amount(), 2 ),
+ 'individual_use' => $coupon->get_individual_use(),
+ 'product_ids' => array_map( 'absint', (array) $coupon->get_product_ids() ),
+ 'exclude_product_ids' => array_map( 'absint', (array) $coupon->get_excluded_product_ids() ),
+ 'usage_limit' => $coupon->get_usage_limit() ? $coupon->get_usage_limit() : null,
+ 'usage_limit_per_user' => $coupon->get_usage_limit_per_user() ? $coupon->get_usage_limit_per_user() : null,
+ 'limit_usage_to_x_items' => (int) $coupon->get_limit_usage_to_x_items(),
+ 'usage_count' => (int) $coupon->get_usage_count(),
+ 'expiry_date' => $this->server->format_datetime( $coupon->get_date_expires() ? $coupon->get_date_expires()->getTimestamp() : 0 ), // API gives UTC times.
+ 'enable_free_shipping' => $coupon->get_free_shipping(),
+ 'product_category_ids' => array_map( 'absint', (array) $coupon->get_product_categories() ),
+ 'exclude_product_category_ids' => array_map( 'absint', (array) $coupon->get_excluded_product_categories() ),
+ 'exclude_sale_items' => $coupon->get_exclude_sale_items(),
+ 'minimum_amount' => wc_format_decimal( $coupon->get_minimum_amount(), 2 ),
+ 'customer_emails' => $coupon->get_email_restrictions(),
+ );
+
+ return array( 'coupon' => apply_filters( 'woocommerce_api_coupon_response', $coupon_data, $coupon, $fields, $this->server ) );
+ }
+
+ /**
+ * Get the total number of coupons
+ *
+ * @since 2.1
+ *
+ * @param array $filter
+ *
+ * @return array|WP_Error
+ */
+ public function get_coupons_count( $filter = array() ) {
+
+ $query = $this->query_coupons( $filter );
+
+ if ( ! current_user_can( 'read_private_shop_coupons' ) ) {
+ return new WP_Error( 'woocommerce_api_user_cannot_read_coupons_count', __( 'You do not have permission to read the coupons count', 'woocommerce' ), array( 'status' => 401 ) );
+ }
+
+ return array( 'count' => (int) $query->found_posts );
+ }
+
+ /**
+ * Get the coupon for the given code
+ *
+ * @since 2.1
+ * @param string $code the coupon code
+ * @param string $fields fields to include in response
+ * @return int|WP_Error
+ */
+ public function get_coupon_by_code( $code, $fields = null ) {
+ global $wpdb;
+
+ $id = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM $wpdb->posts WHERE post_title = %s AND post_type = 'shop_coupon' AND post_status = 'publish' ORDER BY post_date DESC LIMIT 1;", $code ) );
+
+ if ( is_null( $id ) ) {
+ return new WP_Error( 'woocommerce_api_invalid_coupon_code', __( 'Invalid coupon code', 'woocommerce' ), array( 'status' => 404 ) );
+ }
+
+ return $this->get_coupon( $id, $fields );
+ }
+
+ /**
+ * Create a coupon
+ *
+ * @param array $data
+ * @return array
+ */
+ public function create_coupon( $data ) {
+
+ return array();
+ }
+
+ /**
+ * Edit a coupon
+ *
+ * @param int $id the coupon ID
+ * @param array $data
+ * @return array|WP_Error
+ */
+ public function edit_coupon( $id, $data ) {
+
+ $id = $this->validate_request( $id, 'shop_coupon', 'edit' );
+
+ if ( is_wp_error( $id ) ) {
+ return $id;
+ }
+
+ return $this->get_coupon( $id );
+ }
+
+ /**
+ * Delete a coupon
+ *
+ * @param int $id the coupon ID
+ * @param bool $force true to permanently delete coupon, false to move to trash
+ * @return array|WP_Error
+ */
+ public function delete_coupon( $id, $force = false ) {
+
+ $id = $this->validate_request( $id, 'shop_coupon', 'delete' );
+
+ if ( is_wp_error( $id ) ) {
+ return $id;
+ }
+
+ return $this->delete( $id, 'shop_coupon', ( 'true' === $force ) );
+ }
+
+ /**
+ * Helper method to get coupon post objects
+ *
+ * @since 2.1
+ * @param array $args request arguments for filtering query
+ * @return WP_Query
+ */
+ private function query_coupons( $args ) {
+
+ // set base query arguments
+ $query_args = array(
+ 'fields' => 'ids',
+ 'post_type' => 'shop_coupon',
+ 'post_status' => 'publish',
+ );
+
+ $query_args = $this->merge_query_args( $query_args, $args );
+
+ return new WP_Query( $query_args );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/v1/class-wc-api-customers.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/v1/class-wc-api-customers.php
new file mode 100644
index 0000000..1860815
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/v1/class-wc-api-customers.php
@@ -0,0 +1,481 @@
+
+ * GET /customers/
, note that coupon codes can contain spaces, dashes and underscores
+ $routes[ $this->base . '/code/(?P
\w[\w\s\-]*)' ] = array(
+ array( array( $this, 'get_coupon_by_code' ), WC_API_Server::READABLE ),
+ );
+
+ # POST|PUT /coupons/bulk
+ $routes[ $this->base . '/bulk' ] = array(
+ array( array( $this, 'bulk' ), WC_API_Server::EDITABLE | WC_API_Server::ACCEPT_DATA ),
+ );
+
+ return $routes;
+ }
+
+ /**
+ * Get all coupons
+ *
+ * @since 2.1
+ * @param string $fields
+ * @param array $filter
+ * @param int $page
+ * @return array
+ */
+ public function get_coupons( $fields = null, $filter = array(), $page = 1 ) {
+
+ $filter['page'] = $page;
+
+ $query = $this->query_coupons( $filter );
+
+ $coupons = array();
+
+ foreach ( $query->posts as $coupon_id ) {
+
+ if ( ! $this->is_readable( $coupon_id ) ) {
+ continue;
+ }
+
+ $coupons[] = current( $this->get_coupon( $coupon_id, $fields ) );
+ }
+
+ $this->server->add_pagination_headers( $query );
+
+ return array( 'coupons' => $coupons );
+ }
+
+ /**
+ * Get the coupon for the given ID
+ *
+ * @since 2.1
+ * @param int $id the coupon ID
+ * @param string $fields fields to include in response
+ * @return array|WP_Error
+ */
+ public function get_coupon( $id, $fields = null ) {
+ try {
+
+ $id = $this->validate_request( $id, 'shop_coupon', 'read' );
+
+ if ( is_wp_error( $id ) ) {
+ return $id;
+ }
+
+ $coupon = new WC_Coupon( $id );
+
+ if ( 0 === $coupon->get_id() ) {
+ throw new WC_API_Exception( 'woocommerce_api_invalid_coupon_id', __( 'Invalid coupon ID', 'woocommerce' ), 404 );
+ }
+
+ $coupon_data = array(
+ 'id' => $coupon->get_id(),
+ 'code' => $coupon->get_code(),
+ 'type' => $coupon->get_discount_type(),
+ 'created_at' => $this->server->format_datetime( $coupon->get_date_created() ? $coupon->get_date_created()->getTimestamp() : 0 ), // API gives UTC times.
+ 'updated_at' => $this->server->format_datetime( $coupon->get_date_modified() ? $coupon->get_date_modified()->getTimestamp() : 0 ), // API gives UTC times.
+ 'amount' => wc_format_decimal( $coupon->get_amount(), 2 ),
+ 'individual_use' => $coupon->get_individual_use(),
+ 'product_ids' => array_map( 'absint', (array) $coupon->get_product_ids() ),
+ 'exclude_product_ids' => array_map( 'absint', (array) $coupon->get_excluded_product_ids() ),
+ 'usage_limit' => $coupon->get_usage_limit() ? $coupon->get_usage_limit() : null,
+ 'usage_limit_per_user' => $coupon->get_usage_limit_per_user() ? $coupon->get_usage_limit_per_user() : null,
+ 'limit_usage_to_x_items' => (int) $coupon->get_limit_usage_to_x_items(),
+ 'usage_count' => (int) $coupon->get_usage_count(),
+ 'expiry_date' => $coupon->get_date_expires() ? $this->server->format_datetime( $coupon->get_date_expires()->getTimestamp() ) : null, // API gives UTC times.
+ 'enable_free_shipping' => $coupon->get_free_shipping(),
+ 'product_category_ids' => array_map( 'absint', (array) $coupon->get_product_categories() ),
+ 'exclude_product_category_ids' => array_map( 'absint', (array) $coupon->get_excluded_product_categories() ),
+ 'exclude_sale_items' => $coupon->get_exclude_sale_items(),
+ 'minimum_amount' => wc_format_decimal( $coupon->get_minimum_amount(), 2 ),
+ 'maximum_amount' => wc_format_decimal( $coupon->get_maximum_amount(), 2 ),
+ 'customer_emails' => $coupon->get_email_restrictions(),
+ 'description' => $coupon->get_description(),
+ );
+
+ return array( 'coupon' => apply_filters( 'woocommerce_api_coupon_response', $coupon_data, $coupon, $fields, $this->server ) );
+ } catch ( WC_API_Exception $e ) {
+ return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
+ }
+ }
+
+ /**
+ * Get the total number of coupons
+ *
+ * @since 2.1
+ *
+ * @param array $filter
+ *
+ * @return array|WP_Error
+ */
+ public function get_coupons_count( $filter = array() ) {
+ try {
+ if ( ! current_user_can( 'read_private_shop_coupons' ) ) {
+ throw new WC_API_Exception( 'woocommerce_api_user_cannot_read_coupons_count', __( 'You do not have permission to read the coupons count', 'woocommerce' ), 401 );
+ }
+
+ $query = $this->query_coupons( $filter );
+
+ return array( 'count' => (int) $query->found_posts );
+ } catch ( WC_API_Exception $e ) {
+ return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
+ }
+ }
+
+ /**
+ * Get the coupon for the given code
+ *
+ * @since 2.1
+ * @param string $code the coupon code
+ * @param string $fields fields to include in response
+ * @return int|WP_Error
+ */
+ public function get_coupon_by_code( $code, $fields = null ) {
+ global $wpdb;
+
+ try {
+ $id = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM $wpdb->posts WHERE post_title = %s AND post_type = 'shop_coupon' AND post_status = 'publish' ORDER BY post_date DESC LIMIT 1;", $code ) );
+
+ if ( is_null( $id ) ) {
+ throw new WC_API_Exception( 'woocommerce_api_invalid_coupon_code', __( 'Invalid coupon code', 'woocommerce' ), 404 );
+ }
+
+ return $this->get_coupon( $id, $fields );
+ } catch ( WC_API_Exception $e ) {
+ return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
+ }
+ }
+
+ /**
+ * Create a coupon
+ *
+ * @since 2.2
+ *
+ * @param array $data
+ *
+ * @return array|WP_Error
+ */
+ public function create_coupon( $data ) {
+ global $wpdb;
+
+ try {
+ if ( ! isset( $data['coupon'] ) ) {
+ throw new WC_API_Exception( 'woocommerce_api_missing_coupon_data', sprintf( __( 'No %1$s data specified to create %1$s', 'woocommerce' ), 'coupon' ), 400 );
+ }
+
+ $data = $data['coupon'];
+
+ // Check user permission
+ if ( ! current_user_can( 'publish_shop_coupons' ) ) {
+ throw new WC_API_Exception( 'woocommerce_api_user_cannot_create_coupon', __( 'You do not have permission to create coupons', 'woocommerce' ), 401 );
+ }
+
+ $data = apply_filters( 'woocommerce_api_create_coupon_data', $data, $this );
+
+ // Check if coupon code is specified
+ if ( ! isset( $data['code'] ) ) {
+ throw new WC_API_Exception( 'woocommerce_api_missing_coupon_code', sprintf( __( 'Missing parameter %s', 'woocommerce' ), 'code' ), 400 );
+ }
+
+ $coupon_code = wc_format_coupon_code( $data['code'] );
+ $id_from_code = wc_get_coupon_id_by_code( $coupon_code );
+
+ if ( $id_from_code ) {
+ throw new WC_API_Exception( 'woocommerce_api_coupon_code_already_exists', __( 'The coupon code already exists', 'woocommerce' ), 400 );
+ }
+
+ $defaults = array(
+ 'type' => 'fixed_cart',
+ 'amount' => 0,
+ 'individual_use' => false,
+ 'product_ids' => array(),
+ 'exclude_product_ids' => array(),
+ 'usage_limit' => '',
+ 'usage_limit_per_user' => '',
+ 'limit_usage_to_x_items' => '',
+ 'usage_count' => '',
+ 'expiry_date' => '',
+ 'enable_free_shipping' => false,
+ 'product_category_ids' => array(),
+ 'exclude_product_category_ids' => array(),
+ 'exclude_sale_items' => false,
+ 'minimum_amount' => '',
+ 'maximum_amount' => '',
+ 'customer_emails' => array(),
+ 'description' => '',
+ );
+
+ $coupon_data = wp_parse_args( $data, $defaults );
+
+ // Validate coupon types
+ if ( ! in_array( wc_clean( $coupon_data['type'] ), array_keys( wc_get_coupon_types() ) ) ) {
+ throw new WC_API_Exception( 'woocommerce_api_invalid_coupon_type', sprintf( __( 'Invalid coupon type - the coupon type must be any of these: %s', 'woocommerce' ), implode( ', ', array_keys( wc_get_coupon_types() ) ) ), 400 );
+ }
+
+ $new_coupon = array(
+ 'post_title' => $coupon_code,
+ 'post_content' => '',
+ 'post_status' => 'publish',
+ 'post_author' => get_current_user_id(),
+ 'post_type' => 'shop_coupon',
+ 'post_excerpt' => $coupon_data['description'],
+ );
+
+ $id = wp_insert_post( $new_coupon, true );
+
+ if ( is_wp_error( $id ) ) {
+ throw new WC_API_Exception( 'woocommerce_api_cannot_create_coupon', $id->get_error_message(), 400 );
+ }
+
+ // Set coupon meta
+ update_post_meta( $id, 'discount_type', $coupon_data['type'] );
+ update_post_meta( $id, 'coupon_amount', wc_format_decimal( $coupon_data['amount'] ) );
+ update_post_meta( $id, 'individual_use', ( true === $coupon_data['individual_use'] ) ? 'yes' : 'no' );
+ update_post_meta( $id, 'product_ids', implode( ',', array_filter( array_map( 'intval', $coupon_data['product_ids'] ) ) ) );
+ update_post_meta( $id, 'exclude_product_ids', implode( ',', array_filter( array_map( 'intval', $coupon_data['exclude_product_ids'] ) ) ) );
+ update_post_meta( $id, 'usage_limit', absint( $coupon_data['usage_limit'] ) );
+ update_post_meta( $id, 'usage_limit_per_user', absint( $coupon_data['usage_limit_per_user'] ) );
+ update_post_meta( $id, 'limit_usage_to_x_items', absint( $coupon_data['limit_usage_to_x_items'] ) );
+ update_post_meta( $id, 'usage_count', absint( $coupon_data['usage_count'] ) );
+ update_post_meta( $id, 'expiry_date', $this->get_coupon_expiry_date( wc_clean( $coupon_data['expiry_date'] ) ) );
+ update_post_meta( $id, 'date_expires', $this->get_coupon_expiry_date( wc_clean( $coupon_data['expiry_date'] ), true ) );
+ update_post_meta( $id, 'free_shipping', ( true === $coupon_data['enable_free_shipping'] ) ? 'yes' : 'no' );
+ update_post_meta( $id, 'product_categories', array_filter( array_map( 'intval', $coupon_data['product_category_ids'] ) ) );
+ update_post_meta( $id, 'exclude_product_categories', array_filter( array_map( 'intval', $coupon_data['exclude_product_category_ids'] ) ) );
+ update_post_meta( $id, 'exclude_sale_items', ( true === $coupon_data['exclude_sale_items'] ) ? 'yes' : 'no' );
+ update_post_meta( $id, 'minimum_amount', wc_format_decimal( $coupon_data['minimum_amount'] ) );
+ update_post_meta( $id, 'maximum_amount', wc_format_decimal( $coupon_data['maximum_amount'] ) );
+ update_post_meta( $id, 'customer_email', array_filter( array_map( 'sanitize_email', $coupon_data['customer_emails'] ) ) );
+
+ do_action( 'woocommerce_api_create_coupon', $id, $data );
+ do_action( 'woocommerce_new_coupon', $id );
+
+ $this->server->send_status( 201 );
+
+ return $this->get_coupon( $id );
+ } catch ( WC_API_Exception $e ) {
+ return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
+ }
+ }
+
+ /**
+ * Edit a coupon
+ *
+ * @since 2.2
+ *
+ * @param int $id the coupon ID
+ * @param array $data
+ *
+ * @return array|WP_Error
+ */
+ public function edit_coupon( $id, $data ) {
+
+ try {
+ if ( ! isset( $data['coupon'] ) ) {
+ throw new WC_API_Exception( 'woocommerce_api_missing_coupon_data', sprintf( __( 'No %1$s data specified to edit %1$s', 'woocommerce' ), 'coupon' ), 400 );
+ }
+
+ $data = $data['coupon'];
+
+ $id = $this->validate_request( $id, 'shop_coupon', 'edit' );
+
+ if ( is_wp_error( $id ) ) {
+ return $id;
+ }
+
+ $data = apply_filters( 'woocommerce_api_edit_coupon_data', $data, $id, $this );
+
+ if ( isset( $data['code'] ) ) {
+ global $wpdb;
+
+ $coupon_code = wc_format_coupon_code( $data['code'] );
+ $id_from_code = wc_get_coupon_id_by_code( $coupon_code, $id );
+
+ if ( $id_from_code ) {
+ throw new WC_API_Exception( 'woocommerce_api_coupon_code_already_exists', __( 'The coupon code already exists', 'woocommerce' ), 400 );
+ }
+
+ $updated = wp_update_post( array( 'ID' => intval( $id ), 'post_title' => $coupon_code ) );
+
+ if ( 0 === $updated ) {
+ throw new WC_API_Exception( 'woocommerce_api_cannot_update_coupon', __( 'Failed to update coupon', 'woocommerce' ), 400 );
+ }
+ }
+
+ if ( isset( $data['description'] ) ) {
+ $updated = wp_update_post( array( 'ID' => intval( $id ), 'post_excerpt' => $data['description'] ) );
+
+ if ( 0 === $updated ) {
+ throw new WC_API_Exception( 'woocommerce_api_cannot_update_coupon', __( 'Failed to update coupon', 'woocommerce' ), 400 );
+ }
+ }
+
+ if ( isset( $data['type'] ) ) {
+ // Validate coupon types
+ if ( ! in_array( wc_clean( $data['type'] ), array_keys( wc_get_coupon_types() ) ) ) {
+ throw new WC_API_Exception( 'woocommerce_api_invalid_coupon_type', sprintf( __( 'Invalid coupon type - the coupon type must be any of these: %s', 'woocommerce' ), implode( ', ', array_keys( wc_get_coupon_types() ) ) ), 400 );
+ }
+ update_post_meta( $id, 'discount_type', $data['type'] );
+ }
+
+ if ( isset( $data['amount'] ) ) {
+ update_post_meta( $id, 'coupon_amount', wc_format_decimal( $data['amount'] ) );
+ }
+
+ if ( isset( $data['individual_use'] ) ) {
+ update_post_meta( $id, 'individual_use', ( true === $data['individual_use'] ) ? 'yes' : 'no' );
+ }
+
+ if ( isset( $data['product_ids'] ) ) {
+ update_post_meta( $id, 'product_ids', implode( ',', array_filter( array_map( 'intval', $data['product_ids'] ) ) ) );
+ }
+
+ if ( isset( $data['exclude_product_ids'] ) ) {
+ update_post_meta( $id, 'exclude_product_ids', implode( ',', array_filter( array_map( 'intval', $data['exclude_product_ids'] ) ) ) );
+ }
+
+ if ( isset( $data['usage_limit'] ) ) {
+ update_post_meta( $id, 'usage_limit', absint( $data['usage_limit'] ) );
+ }
+
+ if ( isset( $data['usage_limit_per_user'] ) ) {
+ update_post_meta( $id, 'usage_limit_per_user', absint( $data['usage_limit_per_user'] ) );
+ }
+
+ if ( isset( $data['limit_usage_to_x_items'] ) ) {
+ update_post_meta( $id, 'limit_usage_to_x_items', absint( $data['limit_usage_to_x_items'] ) );
+ }
+
+ if ( isset( $data['usage_count'] ) ) {
+ update_post_meta( $id, 'usage_count', absint( $data['usage_count'] ) );
+ }
+
+ if ( isset( $data['expiry_date'] ) ) {
+ update_post_meta( $id, 'expiry_date', $this->get_coupon_expiry_date( wc_clean( $data['expiry_date'] ) ) );
+ update_post_meta( $id, 'date_expires', $this->get_coupon_expiry_date( wc_clean( $data['expiry_date'] ), true ) );
+ }
+
+ if ( isset( $data['enable_free_shipping'] ) ) {
+ update_post_meta( $id, 'free_shipping', ( true === $data['enable_free_shipping'] ) ? 'yes' : 'no' );
+ }
+
+ if ( isset( $data['product_category_ids'] ) ) {
+ update_post_meta( $id, 'product_categories', array_filter( array_map( 'intval', $data['product_category_ids'] ) ) );
+ }
+
+ if ( isset( $data['exclude_product_category_ids'] ) ) {
+ update_post_meta( $id, 'exclude_product_categories', array_filter( array_map( 'intval', $data['exclude_product_category_ids'] ) ) );
+ }
+
+ if ( isset( $data['exclude_sale_items'] ) ) {
+ update_post_meta( $id, 'exclude_sale_items', ( true === $data['exclude_sale_items'] ) ? 'yes' : 'no' );
+ }
+
+ if ( isset( $data['minimum_amount'] ) ) {
+ update_post_meta( $id, 'minimum_amount', wc_format_decimal( $data['minimum_amount'] ) );
+ }
+
+ if ( isset( $data['maximum_amount'] ) ) {
+ update_post_meta( $id, 'maximum_amount', wc_format_decimal( $data['maximum_amount'] ) );
+ }
+
+ if ( isset( $data['customer_emails'] ) ) {
+ update_post_meta( $id, 'customer_email', array_filter( array_map( 'sanitize_email', $data['customer_emails'] ) ) );
+ }
+
+ do_action( 'woocommerce_api_edit_coupon', $id, $data );
+ do_action( 'woocommerce_update_coupon', $id );
+
+ return $this->get_coupon( $id );
+ } catch ( WC_API_Exception $e ) {
+ return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
+ }
+ }
+
+ /**
+ * Delete a coupon
+ *
+ * @since 2.2
+ * @param int $id the coupon ID
+ * @param bool $force true to permanently delete coupon, false to move to trash
+ * @return array|WP_Error
+ */
+ public function delete_coupon( $id, $force = false ) {
+
+ $id = $this->validate_request( $id, 'shop_coupon', 'delete' );
+
+ if ( is_wp_error( $id ) ) {
+ return $id;
+ }
+
+ do_action( 'woocommerce_api_delete_coupon', $id, $this );
+
+ return $this->delete( $id, 'shop_coupon', ( 'true' === $force ) );
+ }
+
+ /**
+ * expiry_date format
+ *
+ * @since 2.3.0
+ * @param string $expiry_date
+ * @param bool $as_timestamp (default: false)
+ * @return string|int
+ */
+ protected function get_coupon_expiry_date( $expiry_date, $as_timestamp = false ) {
+ if ( '' != $expiry_date ) {
+ if ( $as_timestamp ) {
+ return strtotime( $expiry_date );
+ }
+
+ return date( 'Y-m-d', strtotime( $expiry_date ) );
+ }
+
+ return '';
+ }
+
+ /**
+ * Helper method to get coupon post objects
+ *
+ * @since 2.1
+ * @param array $args request arguments for filtering query
+ * @return WP_Query
+ */
+ private function query_coupons( $args ) {
+
+ // set base query arguments
+ $query_args = array(
+ 'fields' => 'ids',
+ 'post_type' => 'shop_coupon',
+ 'post_status' => 'publish',
+ );
+
+ $query_args = $this->merge_query_args( $query_args, $args );
+
+ return new WP_Query( $query_args );
+ }
+
+ /**
+ * Bulk update or insert coupons
+ * Accepts an array with coupons in the formats supported by
+ * WC_API_Coupons->create_coupon() and WC_API_Coupons->edit_coupon()
+ *
+ * @since 2.4.0
+ *
+ * @param array $data
+ *
+ * @return array|WP_Error
+ */
+ public function bulk( $data ) {
+
+ try {
+ if ( ! isset( $data['coupons'] ) ) {
+ throw new WC_API_Exception( 'woocommerce_api_missing_coupons_data', sprintf( __( 'No %1$s data specified to create/edit %1$s', 'woocommerce' ), 'coupons' ), 400 );
+ }
+
+ $data = $data['coupons'];
+ $limit = apply_filters( 'woocommerce_api_bulk_limit', 100, 'coupons' );
+
+ // Limit bulk operation
+ if ( count( $data ) > $limit ) {
+ throw new WC_API_Exception( 'woocommerce_api_coupons_request_entity_too_large', sprintf( __( 'Unable to accept more than %s items for this request.', 'woocommerce' ), $limit ), 413 );
+ }
+
+ $coupons = array();
+
+ foreach ( $data as $_coupon ) {
+ $coupon_id = 0;
+
+ // Try to get the coupon ID
+ if ( isset( $_coupon['id'] ) ) {
+ $coupon_id = intval( $_coupon['id'] );
+ }
+
+ // Coupon exists / edit coupon
+ if ( $coupon_id ) {
+ $edit = $this->edit_coupon( $coupon_id, array( 'coupon' => $_coupon ) );
+
+ if ( is_wp_error( $edit ) ) {
+ $coupons[] = array(
+ 'id' => $coupon_id,
+ 'error' => array( 'code' => $edit->get_error_code(), 'message' => $edit->get_error_message() ),
+ );
+ } else {
+ $coupons[] = $edit['coupon'];
+ }
+ } else {
+
+ // Coupon don't exists / create coupon
+ $new = $this->create_coupon( array( 'coupon' => $_coupon ) );
+
+ if ( is_wp_error( $new ) ) {
+ $coupons[] = array(
+ 'id' => $coupon_id,
+ 'error' => array( 'code' => $new->get_error_code(), 'message' => $new->get_error_message() ),
+ );
+ } else {
+ $coupons[] = $new['coupon'];
+ }
+ }
+ }
+
+ return array( 'coupons' => apply_filters( 'woocommerce_api_coupons_bulk_response', $coupons, $this ) );
+ } catch ( WC_API_Exception $e ) {
+ return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
+ }
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/v2/class-wc-api-customers.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/v2/class-wc-api-customers.php
new file mode 100644
index 0000000..7598025
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/v2/class-wc-api-customers.php
@@ -0,0 +1,837 @@
+
+ * GET /customers/
, note that coupon codes can contain spaces, dashes and underscores
+ $routes[ $this->base . '/code/(?P
.', 'woocommerce' ) . '\w[\w\s\-]*)' ] = array(
+ array( array( $this, 'get_coupon_by_code' ), WC_API_Server::READABLE ),
+ );
+
+ # POST|PUT /coupons/bulk
+ $routes[ $this->base . '/bulk' ] = array(
+ array( array( $this, 'bulk' ), WC_API_Server::EDITABLE | WC_API_Server::ACCEPT_DATA ),
+ );
+
+ return $routes;
+ }
+
+ /**
+ * Get all coupons
+ *
+ * @since 2.1
+ * @param string $fields
+ * @param array $filter
+ * @param int $page
+ * @return array
+ */
+ public function get_coupons( $fields = null, $filter = array(), $page = 1 ) {
+
+ $filter['page'] = $page;
+
+ $query = $this->query_coupons( $filter );
+
+ $coupons = array();
+
+ foreach ( $query->posts as $coupon_id ) {
+
+ if ( ! $this->is_readable( $coupon_id ) ) {
+ continue;
+ }
+
+ $coupons[] = current( $this->get_coupon( $coupon_id, $fields ) );
+ }
+
+ $this->server->add_pagination_headers( $query );
+
+ return array( 'coupons' => $coupons );
+ }
+
+ /**
+ * Get the coupon for the given ID
+ *
+ * @since 2.1
+ * @param int $id the coupon ID
+ * @param string $fields fields to include in response
+ * @return array|WP_Error
+ */
+ public function get_coupon( $id, $fields = null ) {
+ try {
+
+ $id = $this->validate_request( $id, 'shop_coupon', 'read' );
+
+ if ( is_wp_error( $id ) ) {
+ return $id;
+ }
+
+ $coupon = new WC_Coupon( $id );
+
+ if ( 0 === $coupon->get_id() ) {
+ throw new WC_API_Exception( 'woocommerce_api_invalid_coupon_id', __( 'Invalid coupon ID', 'woocommerce' ), 404 );
+ }
+
+ $coupon_data = array(
+ 'id' => $coupon->get_id(),
+ 'code' => $coupon->get_code(),
+ 'type' => $coupon->get_discount_type(),
+ 'created_at' => $this->server->format_datetime( $coupon->get_date_created() ? $coupon->get_date_created()->getTimestamp() : 0 ), // API gives UTC times.
+ 'updated_at' => $this->server->format_datetime( $coupon->get_date_modified() ? $coupon->get_date_modified()->getTimestamp() : 0 ), // API gives UTC times.
+ 'amount' => wc_format_decimal( $coupon->get_amount(), 2 ),
+ 'individual_use' => $coupon->get_individual_use(),
+ 'product_ids' => array_map( 'absint', (array) $coupon->get_product_ids() ),
+ 'exclude_product_ids' => array_map( 'absint', (array) $coupon->get_excluded_product_ids() ),
+ 'usage_limit' => $coupon->get_usage_limit() ? $coupon->get_usage_limit() : null,
+ 'usage_limit_per_user' => $coupon->get_usage_limit_per_user() ? $coupon->get_usage_limit_per_user() : null,
+ 'limit_usage_to_x_items' => (int) $coupon->get_limit_usage_to_x_items(),
+ 'usage_count' => (int) $coupon->get_usage_count(),
+ 'expiry_date' => $coupon->get_date_expires() ? $this->server->format_datetime( $coupon->get_date_expires()->getTimestamp() ) : null, // API gives UTC times.
+ 'enable_free_shipping' => $coupon->get_free_shipping(),
+ 'product_category_ids' => array_map( 'absint', (array) $coupon->get_product_categories() ),
+ 'exclude_product_category_ids' => array_map( 'absint', (array) $coupon->get_excluded_product_categories() ),
+ 'exclude_sale_items' => $coupon->get_exclude_sale_items(),
+ 'minimum_amount' => wc_format_decimal( $coupon->get_minimum_amount(), 2 ),
+ 'maximum_amount' => wc_format_decimal( $coupon->get_maximum_amount(), 2 ),
+ 'customer_emails' => $coupon->get_email_restrictions(),
+ 'description' => $coupon->get_description(),
+ );
+
+ return array( 'coupon' => apply_filters( 'woocommerce_api_coupon_response', $coupon_data, $coupon, $fields, $this->server ) );
+ } catch ( WC_API_Exception $e ) {
+ return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
+ }
+ }
+
+ /**
+ * Get the total number of coupons
+ *
+ * @since 2.1
+ * @param array $filter
+ * @return array|WP_Error
+ */
+ public function get_coupons_count( $filter = array() ) {
+ try {
+ if ( ! current_user_can( 'read_private_shop_coupons' ) ) {
+ throw new WC_API_Exception( 'woocommerce_api_user_cannot_read_coupons_count', __( 'You do not have permission to read the coupons count', 'woocommerce' ), 401 );
+ }
+
+ $query = $this->query_coupons( $filter );
+
+ return array( 'count' => (int) $query->found_posts );
+ } catch ( WC_API_Exception $e ) {
+ return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
+ }
+ }
+
+ /**
+ * Get the coupon for the given code
+ *
+ * @since 2.1
+ * @param string $code the coupon code
+ * @param string $fields fields to include in response
+ * @return int|WP_Error
+ */
+ public function get_coupon_by_code( $code, $fields = null ) {
+ global $wpdb;
+
+ try {
+ $id = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM $wpdb->posts WHERE post_title = %s AND post_type = 'shop_coupon' AND post_status = 'publish' ORDER BY post_date DESC LIMIT 1;", $code ) );
+
+ if ( is_null( $id ) ) {
+ throw new WC_API_Exception( 'woocommerce_api_invalid_coupon_code', __( 'Invalid coupon code', 'woocommerce' ), 404 );
+ }
+
+ return $this->get_coupon( $id, $fields );
+ } catch ( WC_API_Exception $e ) {
+ return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
+ }
+ }
+
+ /**
+ * Create a coupon
+ *
+ * @since 2.2
+ *
+ * @param array $data
+ *
+ * @return array|WP_Error
+ */
+ public function create_coupon( $data ) {
+ global $wpdb;
+
+ try {
+ if ( ! isset( $data['coupon'] ) ) {
+ throw new WC_API_Exception( 'woocommerce_api_missing_coupon_data', sprintf( __( 'No %1$s data specified to create %1$s', 'woocommerce' ), 'coupon' ), 400 );
+ }
+
+ $data = $data['coupon'];
+
+ // Check user permission
+ if ( ! current_user_can( 'publish_shop_coupons' ) ) {
+ throw new WC_API_Exception( 'woocommerce_api_user_cannot_create_coupon', __( 'You do not have permission to create coupons', 'woocommerce' ), 401 );
+ }
+
+ $data = apply_filters( 'woocommerce_api_create_coupon_data', $data, $this );
+
+ // Check if coupon code is specified
+ if ( ! isset( $data['code'] ) ) {
+ throw new WC_API_Exception( 'woocommerce_api_missing_coupon_code', sprintf( __( 'Missing parameter %s', 'woocommerce' ), 'code' ), 400 );
+ }
+
+ $coupon_code = wc_format_coupon_code( $data['code'] );
+ $id_from_code = wc_get_coupon_id_by_code( $coupon_code );
+
+ if ( $id_from_code ) {
+ throw new WC_API_Exception( 'woocommerce_api_coupon_code_already_exists', __( 'The coupon code already exists', 'woocommerce' ), 400 );
+ }
+
+ $defaults = array(
+ 'type' => 'fixed_cart',
+ 'amount' => 0,
+ 'individual_use' => false,
+ 'product_ids' => array(),
+ 'exclude_product_ids' => array(),
+ 'usage_limit' => '',
+ 'usage_limit_per_user' => '',
+ 'limit_usage_to_x_items' => '',
+ 'usage_count' => '',
+ 'expiry_date' => '',
+ 'enable_free_shipping' => false,
+ 'product_category_ids' => array(),
+ 'exclude_product_category_ids' => array(),
+ 'exclude_sale_items' => false,
+ 'minimum_amount' => '',
+ 'maximum_amount' => '',
+ 'customer_emails' => array(),
+ 'description' => '',
+ );
+
+ $coupon_data = wp_parse_args( $data, $defaults );
+
+ // Validate coupon types
+ if ( ! in_array( wc_clean( $coupon_data['type'] ), array_keys( wc_get_coupon_types() ) ) ) {
+ throw new WC_API_Exception( 'woocommerce_api_invalid_coupon_type', sprintf( __( 'Invalid coupon type - the coupon type must be any of these: %s', 'woocommerce' ), implode( ', ', array_keys( wc_get_coupon_types() ) ) ), 400 );
+ }
+
+ $new_coupon = array(
+ 'post_title' => $coupon_code,
+ 'post_content' => '',
+ 'post_status' => 'publish',
+ 'post_author' => get_current_user_id(),
+ 'post_type' => 'shop_coupon',
+ 'post_excerpt' => $coupon_data['description'],
+ );
+
+ $id = wp_insert_post( $new_coupon, true );
+
+ if ( is_wp_error( $id ) ) {
+ throw new WC_API_Exception( 'woocommerce_api_cannot_create_coupon', $id->get_error_message(), 400 );
+ }
+
+ // Set coupon meta
+ update_post_meta( $id, 'discount_type', $coupon_data['type'] );
+ update_post_meta( $id, 'coupon_amount', wc_format_decimal( $coupon_data['amount'] ) );
+ update_post_meta( $id, 'individual_use', ( true === $coupon_data['individual_use'] ) ? 'yes' : 'no' );
+ update_post_meta( $id, 'product_ids', implode( ',', array_filter( array_map( 'intval', $coupon_data['product_ids'] ) ) ) );
+ update_post_meta( $id, 'exclude_product_ids', implode( ',', array_filter( array_map( 'intval', $coupon_data['exclude_product_ids'] ) ) ) );
+ update_post_meta( $id, 'usage_limit', absint( $coupon_data['usage_limit'] ) );
+ update_post_meta( $id, 'usage_limit_per_user', absint( $coupon_data['usage_limit_per_user'] ) );
+ update_post_meta( $id, 'limit_usage_to_x_items', absint( $coupon_data['limit_usage_to_x_items'] ) );
+ update_post_meta( $id, 'usage_count', absint( $coupon_data['usage_count'] ) );
+ update_post_meta( $id, 'expiry_date', $this->get_coupon_expiry_date( wc_clean( $coupon_data['expiry_date'] ) ) );
+ update_post_meta( $id, 'date_expires', $this->get_coupon_expiry_date( wc_clean( $coupon_data['expiry_date'] ), true ) );
+ update_post_meta( $id, 'free_shipping', ( true === $coupon_data['enable_free_shipping'] ) ? 'yes' : 'no' );
+ update_post_meta( $id, 'product_categories', array_filter( array_map( 'intval', $coupon_data['product_category_ids'] ) ) );
+ update_post_meta( $id, 'exclude_product_categories', array_filter( array_map( 'intval', $coupon_data['exclude_product_category_ids'] ) ) );
+ update_post_meta( $id, 'exclude_sale_items', ( true === $coupon_data['exclude_sale_items'] ) ? 'yes' : 'no' );
+ update_post_meta( $id, 'minimum_amount', wc_format_decimal( $coupon_data['minimum_amount'] ) );
+ update_post_meta( $id, 'maximum_amount', wc_format_decimal( $coupon_data['maximum_amount'] ) );
+ update_post_meta( $id, 'customer_email', array_filter( array_map( 'sanitize_email', $coupon_data['customer_emails'] ) ) );
+
+ do_action( 'woocommerce_api_create_coupon', $id, $data );
+ do_action( 'woocommerce_new_coupon', $id );
+
+ $this->server->send_status( 201 );
+
+ return $this->get_coupon( $id );
+ } catch ( WC_API_Exception $e ) {
+ return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
+ }
+ }
+
+ /**
+ * Edit a coupon
+ *
+ * @since 2.2
+ *
+ * @param int $id the coupon ID
+ * @param array $data
+ *
+ * @return array|WP_Error
+ */
+ public function edit_coupon( $id, $data ) {
+
+ try {
+ if ( ! isset( $data['coupon'] ) ) {
+ throw new WC_API_Exception( 'woocommerce_api_missing_coupon_data', sprintf( __( 'No %1$s data specified to edit %1$s', 'woocommerce' ), 'coupon' ), 400 );
+ }
+
+ $data = $data['coupon'];
+
+ $id = $this->validate_request( $id, 'shop_coupon', 'edit' );
+
+ if ( is_wp_error( $id ) ) {
+ return $id;
+ }
+
+ $data = apply_filters( 'woocommerce_api_edit_coupon_data', $data, $id, $this );
+
+ if ( isset( $data['code'] ) ) {
+ global $wpdb;
+
+ $coupon_code = wc_format_coupon_code( $data['code'] );
+ $id_from_code = wc_get_coupon_id_by_code( $coupon_code, $id );
+
+ if ( $id_from_code ) {
+ throw new WC_API_Exception( 'woocommerce_api_coupon_code_already_exists', __( 'The coupon code already exists', 'woocommerce' ), 400 );
+ }
+
+ $updated = wp_update_post( array( 'ID' => intval( $id ), 'post_title' => $coupon_code ) );
+
+ if ( 0 === $updated ) {
+ throw new WC_API_Exception( 'woocommerce_api_cannot_update_coupon', __( 'Failed to update coupon', 'woocommerce' ), 400 );
+ }
+ }
+
+ if ( isset( $data['description'] ) ) {
+ $updated = wp_update_post( array( 'ID' => intval( $id ), 'post_excerpt' => $data['description'] ) );
+
+ if ( 0 === $updated ) {
+ throw new WC_API_Exception( 'woocommerce_api_cannot_update_coupon', __( 'Failed to update coupon', 'woocommerce' ), 400 );
+ }
+ }
+
+ if ( isset( $data['type'] ) ) {
+ // Validate coupon types
+ if ( ! in_array( wc_clean( $data['type'] ), array_keys( wc_get_coupon_types() ) ) ) {
+ throw new WC_API_Exception( 'woocommerce_api_invalid_coupon_type', sprintf( __( 'Invalid coupon type - the coupon type must be any of these: %s', 'woocommerce' ), implode( ', ', array_keys( wc_get_coupon_types() ) ) ), 400 );
+ }
+ update_post_meta( $id, 'discount_type', $data['type'] );
+ }
+
+ if ( isset( $data['amount'] ) ) {
+ update_post_meta( $id, 'coupon_amount', wc_format_decimal( $data['amount'] ) );
+ }
+
+ if ( isset( $data['individual_use'] ) ) {
+ update_post_meta( $id, 'individual_use', ( true === $data['individual_use'] ) ? 'yes' : 'no' );
+ }
+
+ if ( isset( $data['product_ids'] ) ) {
+ update_post_meta( $id, 'product_ids', implode( ',', array_filter( array_map( 'intval', $data['product_ids'] ) ) ) );
+ }
+
+ if ( isset( $data['exclude_product_ids'] ) ) {
+ update_post_meta( $id, 'exclude_product_ids', implode( ',', array_filter( array_map( 'intval', $data['exclude_product_ids'] ) ) ) );
+ }
+
+ if ( isset( $data['usage_limit'] ) ) {
+ update_post_meta( $id, 'usage_limit', absint( $data['usage_limit'] ) );
+ }
+
+ if ( isset( $data['usage_limit_per_user'] ) ) {
+ update_post_meta( $id, 'usage_limit_per_user', absint( $data['usage_limit_per_user'] ) );
+ }
+
+ if ( isset( $data['limit_usage_to_x_items'] ) ) {
+ update_post_meta( $id, 'limit_usage_to_x_items', absint( $data['limit_usage_to_x_items'] ) );
+ }
+
+ if ( isset( $data['usage_count'] ) ) {
+ update_post_meta( $id, 'usage_count', absint( $data['usage_count'] ) );
+ }
+
+ if ( isset( $data['expiry_date'] ) ) {
+ update_post_meta( $id, 'expiry_date', $this->get_coupon_expiry_date( wc_clean( $data['expiry_date'] ) ) );
+ update_post_meta( $id, 'date_expires', $this->get_coupon_expiry_date( wc_clean( $data['expiry_date'] ), true ) );
+ }
+
+ if ( isset( $data['enable_free_shipping'] ) ) {
+ update_post_meta( $id, 'free_shipping', ( true === $data['enable_free_shipping'] ) ? 'yes' : 'no' );
+ }
+
+ if ( isset( $data['product_category_ids'] ) ) {
+ update_post_meta( $id, 'product_categories', array_filter( array_map( 'intval', $data['product_category_ids'] ) ) );
+ }
+
+ if ( isset( $data['exclude_product_category_ids'] ) ) {
+ update_post_meta( $id, 'exclude_product_categories', array_filter( array_map( 'intval', $data['exclude_product_category_ids'] ) ) );
+ }
+
+ if ( isset( $data['exclude_sale_items'] ) ) {
+ update_post_meta( $id, 'exclude_sale_items', ( true === $data['exclude_sale_items'] ) ? 'yes' : 'no' );
+ }
+
+ if ( isset( $data['minimum_amount'] ) ) {
+ update_post_meta( $id, 'minimum_amount', wc_format_decimal( $data['minimum_amount'] ) );
+ }
+
+ if ( isset( $data['maximum_amount'] ) ) {
+ update_post_meta( $id, 'maximum_amount', wc_format_decimal( $data['maximum_amount'] ) );
+ }
+
+ if ( isset( $data['customer_emails'] ) ) {
+ update_post_meta( $id, 'customer_email', array_filter( array_map( 'sanitize_email', $data['customer_emails'] ) ) );
+ }
+
+ do_action( 'woocommerce_api_edit_coupon', $id, $data );
+ do_action( 'woocommerce_update_coupon', $id );
+
+ return $this->get_coupon( $id );
+ } catch ( WC_API_Exception $e ) {
+ return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
+ }
+ }
+
+ /**
+ * Delete a coupon
+ *
+ * @since 2.2
+ *
+ * @param int $id the coupon ID
+ * @param bool $force true to permanently delete coupon, false to move to trash
+ *
+ * @return array|int|WP_Error
+ */
+ public function delete_coupon( $id, $force = false ) {
+
+ $id = $this->validate_request( $id, 'shop_coupon', 'delete' );
+
+ if ( is_wp_error( $id ) ) {
+ return $id;
+ }
+
+ do_action( 'woocommerce_api_delete_coupon', $id, $this );
+
+ return $this->delete( $id, 'shop_coupon', ( 'true' === $force ) );
+ }
+
+ /**
+ * expiry_date format
+ *
+ * @since 2.3.0
+ * @param string $expiry_date
+ * @param bool $as_timestamp (default: false)
+ * @return string|int
+ */
+ protected function get_coupon_expiry_date( $expiry_date, $as_timestamp = false ) {
+ if ( '' != $expiry_date ) {
+ if ( $as_timestamp ) {
+ return strtotime( $expiry_date );
+ }
+
+ return date( 'Y-m-d', strtotime( $expiry_date ) );
+ }
+
+ return '';
+ }
+
+ /**
+ * Helper method to get coupon post objects
+ *
+ * @since 2.1
+ * @param array $args request arguments for filtering query
+ * @return WP_Query
+ */
+ private function query_coupons( $args ) {
+
+ // set base query arguments
+ $query_args = array(
+ 'fields' => 'ids',
+ 'post_type' => 'shop_coupon',
+ 'post_status' => 'publish',
+ );
+
+ $query_args = $this->merge_query_args( $query_args, $args );
+
+ return new WP_Query( $query_args );
+ }
+
+ /**
+ * Bulk update or insert coupons
+ * Accepts an array with coupons in the formats supported by
+ * WC_API_Coupons->create_coupon() and WC_API_Coupons->edit_coupon()
+ *
+ * @since 2.4.0
+ *
+ * @param array $data
+ *
+ * @return array|WP_Error
+ */
+ public function bulk( $data ) {
+
+ try {
+ if ( ! isset( $data['coupons'] ) ) {
+ throw new WC_API_Exception( 'woocommerce_api_missing_coupons_data', sprintf( __( 'No %1$s data specified to create/edit %1$s', 'woocommerce' ), 'coupons' ), 400 );
+ }
+
+ $data = $data['coupons'];
+ $limit = apply_filters( 'woocommerce_api_bulk_limit', 100, 'coupons' );
+
+ // Limit bulk operation
+ if ( count( $data ) > $limit ) {
+ throw new WC_API_Exception( 'woocommerce_api_coupons_request_entity_too_large', sprintf( __( 'Unable to accept more than %s items for this request.', 'woocommerce' ), $limit ), 413 );
+ }
+
+ $coupons = array();
+
+ foreach ( $data as $_coupon ) {
+ $coupon_id = 0;
+
+ // Try to get the coupon ID
+ if ( isset( $_coupon['id'] ) ) {
+ $coupon_id = intval( $_coupon['id'] );
+ }
+
+ if ( $coupon_id ) {
+
+ // Coupon exists / edit coupon
+ $edit = $this->edit_coupon( $coupon_id, array( 'coupon' => $_coupon ) );
+
+ if ( is_wp_error( $edit ) ) {
+ $coupons[] = array(
+ 'id' => $coupon_id,
+ 'error' => array( 'code' => $edit->get_error_code(), 'message' => $edit->get_error_message() ),
+ );
+ } else {
+ $coupons[] = $edit['coupon'];
+ }
+ } else {
+
+ // Coupon don't exists / create coupon
+ $new = $this->create_coupon( array( 'coupon' => $_coupon ) );
+
+ if ( is_wp_error( $new ) ) {
+ $coupons[] = array(
+ 'id' => $coupon_id,
+ 'error' => array( 'code' => $new->get_error_code(), 'message' => $new->get_error_message() ),
+ );
+ } else {
+ $coupons[] = $new['coupon'];
+ }
+ }
+ }
+
+ return array( 'coupons' => apply_filters( 'woocommerce_api_coupons_bulk_response', $coupons, $this ) );
+ } catch ( WC_API_Exception $e ) {
+ return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
+ }
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/v3/class-wc-api-customers.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/v3/class-wc-api-customers.php
new file mode 100644
index 0000000..2df6fd8
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/legacy/api/v3/class-wc-api-customers.php
@@ -0,0 +1,829 @@
+
+ * GET /customers/
.', 'woocommerce' ) . '
' . __( 'Use [qty]
for the number of items, [cost]
for the total cost of items, and [fee percent="10" min_fee="20" max_fee=""]
for percentage based fees.', 'woocommerce' );
+
+$settings = array(
+ 'title' => array(
+ 'title' => __( 'Method title', 'woocommerce' ),
+ 'type' => 'text',
+ 'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce' ),
+ 'default' => __( 'Flat rate', 'woocommerce' ),
+ 'desc_tip' => true,
+ ),
+ 'tax_status' => array(
+ 'title' => __( 'Tax status', 'woocommerce' ),
+ 'type' => 'select',
+ 'class' => 'wc-enhanced-select',
+ 'default' => 'taxable',
+ 'options' => array(
+ 'taxable' => __( 'Taxable', 'woocommerce' ),
+ 'none' => _x( 'None', 'Tax status', 'woocommerce' ),
+ ),
+ ),
+ 'cost' => array(
+ 'title' => __( 'Cost', 'woocommerce' ),
+ 'type' => 'text',
+ 'placeholder' => '',
+ 'description' => $cost_desc,
+ 'default' => '0',
+ 'desc_tip' => true,
+ 'sanitize_callback' => array( $this, 'sanitize_cost' ),
+ ),
+);
+
+$shipping_classes = WC()->shipping()->get_shipping_classes();
+
+if ( ! empty( $shipping_classes ) ) {
+ $settings['class_costs'] = array(
+ 'title' => __( 'Shipping class costs', 'woocommerce' ),
+ 'type' => 'title',
+ 'default' => '',
+ /* translators: %s: URL for link. */
+ 'description' => sprintf( __( 'These costs can optionally be added based on the product shipping class.', 'woocommerce' ), admin_url( 'admin.php?page=wc-settings&tab=shipping§ion=classes' ) ),
+ );
+ foreach ( $shipping_classes as $shipping_class ) {
+ if ( ! isset( $shipping_class->term_id ) ) {
+ continue;
+ }
+ $settings[ 'class_cost_' . $shipping_class->term_id ] = array(
+ /* translators: %s: shipping class name */
+ 'title' => sprintf( __( '"%s" shipping class cost', 'woocommerce' ), esc_html( $shipping_class->name ) ),
+ 'type' => 'text',
+ 'placeholder' => __( 'N/A', 'woocommerce' ),
+ 'description' => $cost_desc,
+ 'default' => $this->get_option( 'class_cost_' . $shipping_class->slug ), // Before 2.5.0, we used slug here which caused issues with long setting names.
+ 'desc_tip' => true,
+ 'sanitize_callback' => array( $this, 'sanitize_cost' ),
+ );
+ }
+
+ $settings['no_class_cost'] = array(
+ 'title' => __( 'No shipping class cost', 'woocommerce' ),
+ 'type' => 'text',
+ 'placeholder' => __( 'N/A', 'woocommerce' ),
+ 'description' => $cost_desc,
+ 'default' => '',
+ 'desc_tip' => true,
+ 'sanitize_callback' => array( $this, 'sanitize_cost' ),
+ );
+
+ $settings['type'] = array(
+ 'title' => __( 'Calculation type', 'woocommerce' ),
+ 'type' => 'select',
+ 'class' => 'wc-enhanced-select',
+ 'default' => 'class',
+ 'options' => array(
+ 'class' => __( 'Per class: Charge shipping for each shipping class individually', 'woocommerce' ),
+ 'order' => __( 'Per order: Charge shipping for the most expensive shipping class', 'woocommerce' ),
+ ),
+ );
+}
+
+return $settings;
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/free-shipping/class-wc-shipping-free-shipping.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/free-shipping/class-wc-shipping-free-shipping.php
new file mode 100644
index 0000000..fc630e6
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/free-shipping/class-wc-shipping-free-shipping.php
@@ -0,0 +1,245 @@
+id = 'free_shipping';
+ $this->instance_id = absint( $instance_id );
+ $this->method_title = __( 'Free shipping', 'woocommerce' );
+ $this->method_description = __( 'Free shipping is a special method which can be triggered with coupons and minimum spends.', 'woocommerce' );
+ $this->supports = array(
+ 'shipping-zones',
+ 'instance-settings',
+ 'instance-settings-modal',
+ );
+
+ $this->init();
+ }
+
+ /**
+ * Initialize free shipping.
+ */
+ public function init() {
+ // Load the settings.
+ $this->init_form_fields();
+ $this->init_settings();
+
+ // Define user set variables.
+ $this->title = $this->get_option( 'title' );
+ $this->min_amount = $this->get_option( 'min_amount', 0 );
+ $this->requires = $this->get_option( 'requires' );
+ $this->ignore_discounts = $this->get_option( 'ignore_discounts' );
+
+ // Actions.
+ add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
+ add_action( 'admin_footer', array( 'WC_Shipping_Free_Shipping', 'enqueue_admin_js' ), 10 ); // Priority needs to be higher than wc_print_js (25).
+ }
+
+ /**
+ * Init form fields.
+ */
+ public function init_form_fields() {
+ $this->instance_form_fields = array(
+ 'title' => array(
+ 'title' => __( 'Title', 'woocommerce' ),
+ 'type' => 'text',
+ 'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce' ),
+ 'default' => $this->method_title,
+ 'desc_tip' => true,
+ ),
+ 'requires' => array(
+ 'title' => __( 'Free shipping requires...', 'woocommerce' ),
+ 'type' => 'select',
+ 'class' => 'wc-enhanced-select',
+ 'default' => '',
+ 'options' => array(
+ '' => __( 'N/A', 'woocommerce' ),
+ 'coupon' => __( 'A valid free shipping coupon', 'woocommerce' ),
+ 'min_amount' => __( 'A minimum order amount', 'woocommerce' ),
+ 'either' => __( 'A minimum order amount OR a coupon', 'woocommerce' ),
+ 'both' => __( 'A minimum order amount AND a coupon', 'woocommerce' ),
+ ),
+ ),
+ 'min_amount' => array(
+ 'title' => __( 'Minimum order amount', 'woocommerce' ),
+ 'type' => 'price',
+ 'placeholder' => wc_format_localized_price( 0 ),
+ 'description' => __( 'Users will need to spend this amount to get free shipping (if enabled above).', 'woocommerce' ),
+ 'default' => '0',
+ 'desc_tip' => true,
+ ),
+ 'ignore_discounts' => array(
+ 'title' => __( 'Coupons discounts', 'woocommerce' ),
+ 'label' => __( 'Apply minimum order rule before coupon discount', 'woocommerce' ),
+ 'type' => 'checkbox',
+ 'description' => __( 'If checked, free shipping would be available based on pre-discount order amount.', 'woocommerce' ),
+ 'default' => 'no',
+ 'desc_tip' => true,
+ ),
+ );
+ }
+
+ /**
+ * Get setting form fields for instances of this shipping method within zones.
+ *
+ * @return array
+ */
+ public function get_instance_form_fields() {
+ return parent::get_instance_form_fields();
+ }
+
+ /**
+ * See if free shipping is available based on the package and cart.
+ *
+ * @param array $package Shipping package.
+ * @return bool
+ */
+ public function is_available( $package ) {
+ $has_coupon = false;
+ $has_met_min_amount = false;
+
+ if ( in_array( $this->requires, array( 'coupon', 'either', 'both' ), true ) ) {
+ $coupons = WC()->cart->get_coupons();
+
+ if ( $coupons ) {
+ foreach ( $coupons as $code => $coupon ) {
+ if ( $coupon->is_valid() && $coupon->get_free_shipping() ) {
+ $has_coupon = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if ( in_array( $this->requires, array( 'min_amount', 'either', 'both' ), true ) ) {
+ $total = WC()->cart->get_displayed_subtotal();
+
+ if ( WC()->cart->display_prices_including_tax() ) {
+ $total = $total - WC()->cart->get_discount_tax();
+ }
+
+ if ( 'no' === $this->ignore_discounts ) {
+ $total = $total - WC()->cart->get_discount_total();
+ }
+
+ $total = NumberUtil::round( $total, wc_get_price_decimals() );
+
+ if ( $total >= $this->min_amount ) {
+ $has_met_min_amount = true;
+ }
+ }
+
+ switch ( $this->requires ) {
+ case 'min_amount':
+ $is_available = $has_met_min_amount;
+ break;
+ case 'coupon':
+ $is_available = $has_coupon;
+ break;
+ case 'both':
+ $is_available = $has_met_min_amount && $has_coupon;
+ break;
+ case 'either':
+ $is_available = $has_met_min_amount || $has_coupon;
+ break;
+ default:
+ $is_available = true;
+ break;
+ }
+
+ return apply_filters( 'woocommerce_shipping_' . $this->id . '_is_available', $is_available, $package, $this );
+ }
+
+ /**
+ * Called to calculate shipping rates for this method. Rates can be added using the add_rate() method.
+ *
+ * @uses WC_Shipping_Method::add_rate()
+ *
+ * @param array $package Shipping package.
+ */
+ public function calculate_shipping( $package = array() ) {
+ $this->add_rate(
+ array(
+ 'label' => $this->title,
+ 'cost' => 0,
+ 'taxes' => false,
+ 'package' => $package,
+ )
+ );
+ }
+
+ /**
+ * Enqueue JS to handle free shipping options.
+ *
+ * Static so that's enqueued only once.
+ */
+ public static function enqueue_admin_js() {
+ wc_enqueue_js(
+ "jQuery( function( $ ) {
+ function wcFreeShippingShowHideMinAmountField( el ) {
+ var form = $( el ).closest( 'form' );
+ var minAmountField = $( '#woocommerce_free_shipping_min_amount', form ).closest( 'tr' );
+ var ignoreDiscountField = $( '#woocommerce_free_shipping_ignore_discounts', form ).closest( 'tr' );
+ if ( 'coupon' === $( el ).val() || '' === $( el ).val() ) {
+ minAmountField.hide();
+ ignoreDiscountField.hide();
+ } else {
+ minAmountField.show();
+ ignoreDiscountField.show();
+ }
+ }
+
+ $( document.body ).on( 'change', '#woocommerce_free_shipping_requires', function() {
+ wcFreeShippingShowHideMinAmountField( this );
+ });
+
+ // Change while load.
+ $( '#woocommerce_free_shipping_requires' ).change();
+ $( document.body ).on( 'wc_backbone_modal_loaded', function( evt, target ) {
+ if ( 'wc-modal-shipping-method-settings' === target ) {
+ wcFreeShippingShowHideMinAmountField( $( '#wc-backbone-modal-dialog #woocommerce_free_shipping_requires', evt.currentTarget ) );
+ }
+ } );
+ });"
+ );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/legacy-flat-rate/class-wc-shipping-legacy-flat-rate.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/legacy-flat-rate/class-wc-shipping-legacy-flat-rate.php
new file mode 100644
index 0000000..1f579c4
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/legacy-flat-rate/class-wc-shipping-legacy-flat-rate.php
@@ -0,0 +1,411 @@
+id = 'legacy_flat_rate';
+ $this->method_title = __( 'Flat rate (legacy)', 'woocommerce' );
+ /* translators: %s: Admin shipping settings URL */
+ $this->method_description = '' . sprintf( __( 'This method is deprecated in 2.6.0 and will be removed in future versions - we recommend disabling it and instead setting up a new rate within your Shipping zones.', 'woocommerce' ), admin_url( 'admin.php?page=wc-settings&tab=shipping' ) ) . '';
+ $this->init();
+
+ add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
+ add_action( 'woocommerce_flat_rate_shipping_add_rate', array( $this, 'calculate_extra_shipping' ), 10, 2 );
+ }
+
+ /**
+ * Process and redirect if disabled.
+ */
+ public function process_admin_options() {
+ parent::process_admin_options();
+
+ if ( 'no' === $this->settings['enabled'] ) {
+ wp_redirect( admin_url( 'admin.php?page=wc-settings&tab=shipping§ion=options' ) );
+ exit;
+ }
+ }
+
+ /**
+ * Return the name of the option in the WP DB.
+ *
+ * @since 2.6.0
+ * @return string
+ */
+ public function get_option_key() {
+ return $this->plugin_id . 'flat_rate_settings';
+ }
+
+ /**
+ * Init function.
+ */
+ public function init() {
+ // Load the settings.
+ $this->init_form_fields();
+ $this->init_settings();
+
+ // Define user set variables.
+ $this->title = $this->get_option( 'title' );
+ $this->availability = $this->get_option( 'availability' );
+ $this->countries = $this->get_option( 'countries' );
+ $this->tax_status = $this->get_option( 'tax_status' );
+ $this->cost = $this->get_option( 'cost' );
+ $this->type = $this->get_option( 'type', 'class' );
+ $this->options = $this->get_option( 'options', false ); // @deprecated 2.4.0
+ }
+
+ /**
+ * Initialise Settings Form Fields.
+ */
+ public function init_form_fields() {
+ $this->form_fields = include __DIR__ . '/includes/settings-flat-rate.php';
+ }
+
+ /**
+ * Evaluate a cost from a sum/string.
+ *
+ * @param string $sum Sum to evaluate.
+ * @param array $args Arguments.
+ * @return string
+ */
+ protected function evaluate_cost( $sum, $args = array() ) {
+ include_once WC()->plugin_path() . '/includes/libraries/class-wc-eval-math.php';
+
+ $locale = localeconv();
+ $decimals = array( wc_get_price_decimal_separator(), $locale['decimal_point'], $locale['mon_decimal_point'] );
+
+ $this->fee_cost = $args['cost'];
+
+ // Expand shortcodes.
+ add_shortcode( 'fee', array( $this, 'fee' ) );
+
+ $sum = do_shortcode(
+ str_replace(
+ array(
+ '[qty]',
+ '[cost]',
+ ),
+ array(
+ $args['qty'],
+ $args['cost'],
+ ),
+ $sum
+ )
+ );
+
+ remove_shortcode( 'fee', array( $this, 'fee' ) );
+
+ // Remove whitespace from string.
+ $sum = preg_replace( '/\s+/', '', $sum );
+
+ // Remove locale from string.
+ $sum = str_replace( $decimals, '.', $sum );
+
+ // Trim invalid start/end characters.
+ $sum = rtrim( ltrim( $sum, "\t\n\r\0\x0B+*/" ), "\t\n\r\0\x0B+-*/" );
+
+ // Do the math.
+ return $sum ? WC_Eval_Math::evaluate( $sum ) : 0;
+ }
+
+ /**
+ * Work out fee (shortcode).
+ *
+ * @param array $atts Shortcode attributes.
+ * @return string
+ */
+ public function fee( $atts ) {
+ $atts = shortcode_atts(
+ array(
+ 'percent' => '',
+ 'min_fee' => '',
+ ),
+ $atts,
+ 'fee'
+ );
+
+ $calculated_fee = 0;
+
+ if ( $atts['percent'] ) {
+ $calculated_fee = $this->fee_cost * ( floatval( $atts['percent'] ) / 100 );
+ }
+
+ if ( $atts['min_fee'] && $calculated_fee < $atts['min_fee'] ) {
+ $calculated_fee = $atts['min_fee'];
+ }
+
+ return $calculated_fee;
+ }
+
+ /**
+ * Calculate shipping.
+ *
+ * @param array $package (default: array()).
+ */
+ public function calculate_shipping( $package = array() ) {
+ $rate = array(
+ 'id' => $this->id,
+ 'label' => $this->title,
+ 'cost' => 0,
+ 'package' => $package,
+ );
+
+ // Calculate the costs.
+ $has_costs = false; // True when a cost is set. False if all costs are blank strings.
+ $cost = $this->get_option( 'cost' );
+
+ if ( '' !== $cost ) {
+ $has_costs = true;
+ $rate['cost'] = $this->evaluate_cost(
+ $cost,
+ array(
+ 'qty' => $this->get_package_item_qty( $package ),
+ 'cost' => $package['contents_cost'],
+ )
+ );
+ }
+
+ // Add shipping class costs.
+ $found_shipping_classes = $this->find_shipping_classes( $package );
+ $highest_class_cost = 0;
+
+ foreach ( $found_shipping_classes as $shipping_class => $products ) {
+ // Also handles BW compatibility when slugs were used instead of ids.
+ $shipping_class_term = get_term_by( 'slug', $shipping_class, 'product_shipping_class' );
+ $class_cost_string = $shipping_class_term && $shipping_class_term->term_id ? $this->get_option( 'class_cost_' . $shipping_class_term->term_id, $this->get_option( 'class_cost_' . $shipping_class, '' ) ) : $this->get_option( 'no_class_cost', '' );
+
+ if ( '' === $class_cost_string ) {
+ continue;
+ }
+
+ $has_costs = true;
+ $class_cost = $this->evaluate_cost(
+ $class_cost_string,
+ array(
+ 'qty' => array_sum( wp_list_pluck( $products, 'quantity' ) ),
+ 'cost' => array_sum( wp_list_pluck( $products, 'line_total' ) ),
+ )
+ );
+
+ if ( 'class' === $this->type ) {
+ $rate['cost'] += $class_cost;
+ } else {
+ $highest_class_cost = $class_cost > $highest_class_cost ? $class_cost : $highest_class_cost;
+ }
+ }
+
+ if ( 'order' === $this->type && $highest_class_cost ) {
+ $rate['cost'] += $highest_class_cost;
+ }
+
+ $rate['package'] = $package;
+
+ // Add the rate.
+ if ( $has_costs ) {
+ $this->add_rate( $rate );
+ }
+
+ /**
+ * Developers can add additional flat rates based on this one via this action since @version 2.4.
+ *
+ * Previously there were (overly complex) options to add additional rates however this was not user.
+ * friendly and goes against what Flat Rate Shipping was originally intended for.
+ *
+ * This example shows how you can add an extra rate based on this flat rate via custom function:
+ *
+ * add_action( 'woocommerce_flat_rate_shipping_add_rate', 'add_another_custom_flat_rate', 10, 2 );
+ *
+ * function add_another_custom_flat_rate( $method, $rate ) {
+ * $new_rate = $rate;
+ * $new_rate['id'] .= ':' . 'custom_rate_name'; // Append a custom ID.
+ * $new_rate['label'] = 'Rushed Shipping'; // Rename to 'Rushed Shipping'.
+ * $new_rate['cost'] += 2; // Add $2 to the cost.
+ *
+ * // Add it to WC.
+ * $method->add_rate( $new_rate );
+ * }.
+ */
+ do_action( 'woocommerce_flat_rate_shipping_add_rate', $this, $rate );
+ }
+
+ /**
+ * Get items in package.
+ *
+ * @param array $package Package information.
+ * @return int
+ */
+ public function get_package_item_qty( $package ) {
+ $total_quantity = 0;
+ foreach ( $package['contents'] as $item_id => $values ) {
+ if ( $values['quantity'] > 0 && $values['data']->needs_shipping() ) {
+ $total_quantity += $values['quantity'];
+ }
+ }
+ return $total_quantity;
+ }
+
+ /**
+ * Finds and returns shipping classes and the products with said class.
+ *
+ * @param mixed $package Package information.
+ * @return array
+ */
+ public function find_shipping_classes( $package ) {
+ $found_shipping_classes = array();
+
+ foreach ( $package['contents'] as $item_id => $values ) {
+ if ( $values['data']->needs_shipping() ) {
+ $found_class = $values['data']->get_shipping_class();
+
+ if ( ! isset( $found_shipping_classes[ $found_class ] ) ) {
+ $found_shipping_classes[ $found_class ] = array();
+ }
+
+ $found_shipping_classes[ $found_class ][ $item_id ] = $values;
+ }
+ }
+
+ return $found_shipping_classes;
+ }
+
+ /**
+ * Adds extra calculated flat rates.
+ *
+ * @deprecated 2.4.0
+ *
+ * Additional rates defined like this:
+ * Option Name | Additional Cost [+- Percents%] | Per Cost Type (order, class, or item).
+ *
+ * @param null $method Deprecated.
+ * @param array $rate Rate information.
+ */
+ public function calculate_extra_shipping( $method, $rate ) {
+ if ( $this->options ) {
+ $options = array_filter( (array) explode( "\n", $this->options ) );
+
+ foreach ( $options as $option ) {
+ $this_option = array_map( 'trim', explode( WC_DELIMITER, $option ) );
+ if ( count( $this_option ) !== 3 ) {
+ continue;
+ }
+ $extra_rate = $rate;
+ $extra_rate['id'] = $this->id . ':' . urldecode( sanitize_title( $this_option[0] ) );
+ $extra_rate['label'] = $this_option[0];
+ $extra_cost = $this->get_extra_cost( $this_option[1], $this_option[2], $rate['package'] );
+ if ( is_array( $extra_rate['cost'] ) ) {
+ $extra_rate['cost']['order'] = $extra_rate['cost']['order'] + $extra_cost;
+ } else {
+ $extra_rate['cost'] += $extra_cost;
+ }
+
+ $this->add_rate( $extra_rate );
+ }
+ }
+ }
+
+ /**
+ * Calculate the percentage adjustment for each shipping rate.
+ *
+ * @deprecated 2.4.0
+ * @param float $cost Cost.
+ * @param float $percent_adjustment Percent adjusment.
+ * @param string $percent_operator Percent operator.
+ * @param float $base_price Base price.
+ * @return float
+ */
+ public function calc_percentage_adjustment( $cost, $percent_adjustment, $percent_operator, $base_price ) {
+ if ( '+' === $percent_operator ) {
+ $cost += $percent_adjustment * $base_price;
+ } else {
+ $cost -= $percent_adjustment * $base_price;
+ }
+ return $cost;
+ }
+
+ /**
+ * Get extra cost.
+ *
+ * @deprecated 2.4.0
+ * @param string $cost_string Cost string.
+ * @param string $type Type.
+ * @param array $package Package information.
+ * @return float
+ */
+ public function get_extra_cost( $cost_string, $type, $package ) {
+ $cost = $cost_string;
+ $cost_percent = false;
+ // @codingStandardsIgnoreStart
+ $pattern =
+ '/' . // Start regex.
+ '(\d+\.?\d*)' . // Capture digits, optionally capture a `.` and more digits.
+ '\s*' . // Match whitespace.
+ '(\+|-)' . // Capture the operand.
+ '\s*' . // Match whitespace.
+ '(\d+\.?\d*)' . // Capture digits, optionally capture a `.` and more digits.
+ '\%/'; // Match the percent sign & end regex.
+ // @codingStandardsIgnoreEnd
+ if ( preg_match( $pattern, $cost_string, $this_cost_matches ) ) {
+ $cost_operator = $this_cost_matches[2];
+ $cost_percent = $this_cost_matches[3] / 100;
+ $cost = $this_cost_matches[1];
+ }
+ switch ( $type ) {
+ case 'class':
+ $cost = $cost * count( $this->find_shipping_classes( $package ) );
+ break;
+ case 'item':
+ $cost = $cost * $this->get_package_item_qty( $package );
+ break;
+ }
+ if ( $cost_percent ) {
+ switch ( $type ) {
+ case 'class':
+ $shipping_classes = $this->find_shipping_classes( $package );
+ foreach ( $shipping_classes as $shipping_class => $items ) {
+ foreach ( $items as $item_id => $values ) {
+ $cost = $this->calc_percentage_adjustment( $cost, $cost_percent, $cost_operator, $values['line_total'] );
+ }
+ }
+ break;
+ case 'item':
+ foreach ( $package['contents'] as $item_id => $values ) {
+ if ( $values['data']->needs_shipping() ) {
+ $cost = $this->calc_percentage_adjustment( $cost, $cost_percent, $cost_operator, $values['line_total'] );
+ }
+ }
+ break;
+ case 'order':
+ $cost = $this->calc_percentage_adjustment( $cost, $cost_percent, $cost_operator, $package['contents_cost'] );
+ break;
+ }
+ }
+ return $cost;
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/legacy-flat-rate/includes/settings-flat-rate.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/legacy-flat-rate/includes/settings-flat-rate.php
new file mode 100644
index 0000000..de0fd0b
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/legacy-flat-rate/includes/settings-flat-rate.php
@@ -0,0 +1,133 @@
+10.00 * [qty]
' . __( 'Supports the following placeholders: [qty]
= number of items, [cost]
= cost of items, [fee percent="10" min_fee="20"]
= Percentage based fee.', 'woocommerce' );
+
+/**
+ * Settings for flat rate shipping.
+ */
+$settings = array(
+ 'enabled' => array(
+ 'title' => __( 'Enable/Disable', 'woocommerce' ),
+ 'type' => 'checkbox',
+ 'label' => __( 'Once disabled, this legacy method will no longer be available.', 'woocommerce' ),
+ 'default' => 'no',
+ ),
+ 'title' => array(
+ 'title' => __( 'Method title', 'woocommerce' ),
+ 'type' => 'text',
+ 'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce' ),
+ 'default' => __( 'Flat rate', 'woocommerce' ),
+ 'desc_tip' => true,
+ ),
+ 'availability' => array(
+ 'title' => __( 'Availability', 'woocommerce' ),
+ 'type' => 'select',
+ 'default' => 'all',
+ 'class' => 'availability wc-enhanced-select',
+ 'options' => array(
+ 'all' => __( 'All allowed countries', 'woocommerce' ),
+ 'specific' => __( 'Specific Countries', 'woocommerce' ),
+ ),
+ ),
+ 'countries' => array(
+ 'title' => __( 'Specific countries', 'woocommerce' ),
+ 'type' => 'multiselect',
+ 'class' => 'wc-enhanced-select',
+ 'css' => 'width: 400px;',
+ 'default' => '',
+ 'options' => WC()->countries->get_shipping_countries(),
+ 'custom_attributes' => array(
+ 'data-placeholder' => __( 'Select some countries', 'woocommerce' ),
+ ),
+ ),
+ 'tax_status' => array(
+ 'title' => __( 'Tax status', 'woocommerce' ),
+ 'type' => 'select',
+ 'class' => 'wc-enhanced-select',
+ 'default' => 'taxable',
+ 'options' => array(
+ 'taxable' => __( 'Taxable', 'woocommerce' ),
+ 'none' => _x( 'None', 'Tax status', 'woocommerce' ),
+ ),
+ ),
+ 'cost' => array(
+ 'title' => __( 'Cost', 'woocommerce' ),
+ 'type' => 'text',
+ 'placeholder' => '',
+ 'description' => $cost_desc,
+ 'default' => '',
+ 'desc_tip' => true,
+ ),
+);
+
+$shipping_classes = WC()->shipping()->get_shipping_classes();
+
+if ( ! empty( $shipping_classes ) ) {
+ $settings['class_costs'] = array(
+ 'title' => __( 'Shipping class costs', 'woocommerce' ),
+ 'type' => 'title',
+ 'default' => '',
+ /* translators: %s: Admin shipping settings URL */
+ 'description' => sprintf( __( 'These costs can optionally be added based on the product shipping class.', 'woocommerce' ), admin_url( 'admin.php?page=wc-settings&tab=shipping§ion=classes' ) ),
+ );
+ foreach ( $shipping_classes as $shipping_class ) {
+ if ( ! isset( $shipping_class->term_id ) ) {
+ continue;
+ }
+ $settings[ 'class_cost_' . $shipping_class->term_id ] = array(
+ /* translators: %s: shipping class name */
+ 'title' => sprintf( __( '"%s" shipping class cost', 'woocommerce' ), esc_html( $shipping_class->name ) ),
+ 'type' => 'text',
+ 'placeholder' => __( 'N/A', 'woocommerce' ),
+ 'description' => $cost_desc,
+ 'default' => $this->get_option( 'class_cost_' . $shipping_class->slug ), // Before 2.5.0, we used slug here which caused issues with long setting names.
+ 'desc_tip' => true,
+ );
+ }
+ $settings['no_class_cost'] = array(
+ 'title' => __( 'No shipping class cost', 'woocommerce' ),
+ 'type' => 'text',
+ 'placeholder' => __( 'N/A', 'woocommerce' ),
+ 'description' => $cost_desc,
+ 'default' => '',
+ 'desc_tip' => true,
+ );
+ $settings['type'] = array(
+ 'title' => __( 'Calculation type', 'woocommerce' ),
+ 'type' => 'select',
+ 'class' => 'wc-enhanced-select',
+ 'default' => 'class',
+ 'options' => array(
+ 'class' => __( 'Per class: Charge shipping for each shipping class individually', 'woocommerce' ),
+ 'order' => __( 'Per order: Charge shipping for the most expensive shipping class', 'woocommerce' ),
+ ),
+ );
+}
+
+if ( apply_filters( 'woocommerce_enable_deprecated_additional_flat_rates', $this->get_option( 'options', false ) ) ) {
+ $settings['additional_rates'] = array(
+ 'title' => __( 'Additional rates', 'woocommerce' ),
+ 'type' => 'title',
+ 'default' => '',
+ 'description' => __( 'These rates are extra shipping options with additional costs (based on the flat rate).', 'woocommerce' ),
+ );
+ $settings['options'] = array(
+ 'title' => __( 'Additional rates', 'woocommerce' ),
+ 'type' => 'textarea',
+ 'description' => __( 'One per line: Option name | Additional cost [+- Percents] | Per cost type (order, class, or item) Example: Priority mail | 6.95 [+ 0.2%] | order
.', 'woocommerce' ),
+ 'default' => '',
+ 'desc_tip' => true,
+ 'placeholder' => __( 'Option name | Additional cost [+- Percents%] | Per cost type (order, class, or item)', 'woocommerce' ),
+ );
+}
+
+return $settings;
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/legacy-free-shipping/class-wc-shipping-legacy-free-shipping.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/legacy-free-shipping/class-wc-shipping-legacy-free-shipping.php
new file mode 100644
index 0000000..1993426
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/legacy-free-shipping/class-wc-shipping-legacy-free-shipping.php
@@ -0,0 +1,252 @@
+id = 'legacy_free_shipping';
+ $this->method_title = __( 'Free shipping (legacy)', 'woocommerce' );
+ /* translators: %s: Admin shipping settings URL */
+ $this->method_description = '' . sprintf( __( 'This method is deprecated in 2.6.0 and will be removed in future versions - we recommend disabling it and instead setting up a new rate within your Shipping zones.', 'woocommerce' ), admin_url( 'admin.php?page=wc-settings&tab=shipping' ) ) . '';
+ $this->init();
+ }
+
+ /**
+ * Process and redirect if disabled.
+ */
+ public function process_admin_options() {
+ parent::process_admin_options();
+
+ if ( 'no' === $this->settings['enabled'] ) {
+ wp_redirect( admin_url( 'admin.php?page=wc-settings&tab=shipping§ion=options' ) );
+ exit;
+ }
+ }
+
+ /**
+ * Return the name of the option in the WP DB.
+ *
+ * @since 2.6.0
+ * @return string
+ */
+ public function get_option_key() {
+ return $this->plugin_id . 'free_shipping_settings';
+ }
+
+ /**
+ * Init function.
+ */
+ public function init() {
+
+ // Load the settings.
+ $this->init_form_fields();
+ $this->init_settings();
+
+ // Define user set variables.
+ $this->enabled = $this->get_option( 'enabled' );
+ $this->title = $this->get_option( 'title' );
+ $this->min_amount = $this->get_option( 'min_amount', 0 );
+ $this->availability = $this->get_option( 'availability' );
+ $this->countries = $this->get_option( 'countries' );
+ $this->requires = $this->get_option( 'requires' );
+
+ // Actions.
+ add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
+ }
+
+ /**
+ * Initialise Gateway Settings Form Fields.
+ */
+ public function init_form_fields() {
+ $this->form_fields = array(
+ 'enabled' => array(
+ 'title' => __( 'Enable/Disable', 'woocommerce' ),
+ 'type' => 'checkbox',
+ 'label' => __( 'Once disabled, this legacy method will no longer be available.', 'woocommerce' ),
+ 'default' => 'no',
+ ),
+ 'title' => array(
+ 'title' => __( 'Method title', 'woocommerce' ),
+ 'type' => 'text',
+ 'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce' ),
+ 'default' => __( 'Free Shipping', 'woocommerce' ),
+ 'desc_tip' => true,
+ ),
+ 'availability' => array(
+ 'title' => __( 'Method availability', 'woocommerce' ),
+ 'type' => 'select',
+ 'default' => 'all',
+ 'class' => 'availability wc-enhanced-select',
+ 'options' => array(
+ 'all' => __( 'All allowed countries', 'woocommerce' ),
+ 'specific' => __( 'Specific Countries', 'woocommerce' ),
+ ),
+ ),
+ 'countries' => array(
+ 'title' => __( 'Specific countries', 'woocommerce' ),
+ 'type' => 'multiselect',
+ 'class' => 'wc-enhanced-select',
+ 'css' => 'width: 400px;',
+ 'default' => '',
+ 'options' => WC()->countries->get_shipping_countries(),
+ 'custom_attributes' => array(
+ 'data-placeholder' => __( 'Select some countries', 'woocommerce' ),
+ ),
+ ),
+ 'requires' => array(
+ 'title' => __( 'Free shipping requires...', 'woocommerce' ),
+ 'type' => 'select',
+ 'class' => 'wc-enhanced-select',
+ 'default' => '',
+ 'options' => array(
+ '' => __( 'N/A', 'woocommerce' ),
+ 'coupon' => __( 'A valid free shipping coupon', 'woocommerce' ),
+ 'min_amount' => __( 'A minimum order amount', 'woocommerce' ),
+ 'either' => __( 'A minimum order amount OR a coupon', 'woocommerce' ),
+ 'both' => __( 'A minimum order amount AND a coupon', 'woocommerce' ),
+ ),
+ ),
+ 'min_amount' => array(
+ 'title' => __( 'Minimum order amount', 'woocommerce' ),
+ 'type' => 'price',
+ 'placeholder' => wc_format_localized_price( 0 ),
+ 'description' => __( 'Users will need to spend this amount to get free shipping (if enabled above).', 'woocommerce' ),
+ 'default' => '0',
+ 'desc_tip' => true,
+ ),
+ );
+ }
+
+ /**
+ * Check if package is available.
+ *
+ * @param array $package Package information.
+ * @return bool
+ */
+ public function is_available( $package ) {
+ if ( 'no' === $this->enabled ) {
+ return false;
+ }
+
+ if ( 'specific' === $this->availability ) {
+ $ship_to_countries = $this->countries;
+ } else {
+ $ship_to_countries = array_keys( WC()->countries->get_shipping_countries() );
+ }
+
+ if ( is_array( $ship_to_countries ) && ! in_array( $package['destination']['country'], $ship_to_countries, true ) ) {
+ return false;
+ }
+
+ // Enabled logic.
+ $is_available = false;
+ $has_coupon = false;
+ $has_met_min_amount = false;
+
+ if ( in_array( $this->requires, array( 'coupon', 'either', 'both' ), true ) ) {
+ $coupons = WC()->cart->get_coupons();
+
+ if ( $coupons ) {
+ foreach ( $coupons as $code => $coupon ) {
+ if ( $coupon->is_valid() && $coupon->get_free_shipping() ) {
+ $has_coupon = true;
+ }
+ }
+ }
+ }
+
+ if ( in_array( $this->requires, array( 'min_amount', 'either', 'both' ), true ) ) {
+ $total = WC()->cart->get_displayed_subtotal();
+
+ if ( WC()->cart->display_prices_including_tax() ) {
+ $total = NumberUtil::round( $total - ( WC()->cart->get_discount_total() + WC()->cart->get_discount_tax() ), wc_get_price_decimals() );
+ } else {
+ $total = NumberUtil::round( $total - WC()->cart->get_discount_total(), wc_get_price_decimals() );
+ }
+
+ if ( $total >= $this->min_amount ) {
+ $has_met_min_amount = true;
+ }
+ }
+
+ switch ( $this->requires ) {
+ case 'min_amount':
+ if ( $has_met_min_amount ) {
+ $is_available = true;
+ }
+ break;
+ case 'coupon':
+ if ( $has_coupon ) {
+ $is_available = true;
+ }
+ break;
+ case 'both':
+ if ( $has_met_min_amount && $has_coupon ) {
+ $is_available = true;
+ }
+ break;
+ case 'either':
+ if ( $has_met_min_amount || $has_coupon ) {
+ $is_available = true;
+ }
+ break;
+ default:
+ $is_available = true;
+ break;
+ }
+
+ return apply_filters( 'woocommerce_shipping_' . $this->id . '_is_available', $is_available, $package, $this );
+ }
+
+ /**
+ * Calculate shipping.
+ *
+ * @param array $package Package information.
+ */
+ public function calculate_shipping( $package = array() ) {
+ $args = array(
+ 'id' => $this->id,
+ 'label' => $this->title,
+ 'cost' => 0,
+ 'taxes' => false,
+ 'package' => $package,
+ );
+ $this->add_rate( $args );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/legacy-international-delivery/class-wc-shipping-legacy-international-delivery.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/legacy-international-delivery/class-wc-shipping-legacy-international-delivery.php
new file mode 100644
index 0000000..6ddc038
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/legacy-international-delivery/class-wc-shipping-legacy-international-delivery.php
@@ -0,0 +1,85 @@
+id = 'legacy_international_delivery';
+ $this->method_title = __( 'International flat rate (legacy)', 'woocommerce' );
+ /* translators: %s: Admin shipping settings URL */
+ $this->method_description = '' . sprintf( __( 'This method is deprecated in 2.6.0 and will be removed in future versions - we recommend disabling it and instead setting up a new rate within your Shipping zones.', 'woocommerce' ), admin_url( 'admin.php?page=wc-settings&tab=shipping' ) ) . '';
+ $this->init();
+
+ add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
+ }
+
+ /**
+ * Return the name of the option in the WP DB.
+ *
+ * @since 2.6.0
+ * @return string
+ */
+ public function get_option_key() {
+ return $this->plugin_id . 'international_delivery_settings';
+ }
+
+ /**
+ * Initialise settings form fields.
+ */
+ public function init_form_fields() {
+ parent::init_form_fields();
+ $this->form_fields['availability'] = array(
+ 'title' => __( 'Availability', 'woocommerce' ),
+ 'type' => 'select',
+ 'class' => 'wc-enhanced-select',
+ 'description' => '',
+ 'default' => 'including',
+ 'options' => array(
+ 'including' => __( 'Selected countries', 'woocommerce' ),
+ 'excluding' => __( 'Excluding selected countries', 'woocommerce' ),
+ ),
+ );
+ }
+
+ /**
+ * Check if package is available.
+ *
+ * @param array $package Package information.
+ * @return bool
+ */
+ public function is_available( $package ) {
+ if ( 'no' === $this->enabled ) {
+ return false;
+ }
+ if ( 'including' === $this->availability ) {
+ if ( is_array( $this->countries ) && ! in_array( $package['destination']['country'], $this->countries, true ) ) {
+ return false;
+ }
+ } else {
+ if ( is_array( $this->countries ) && ( in_array( $package['destination']['country'], $this->countries, true ) || ! $package['destination']['country'] ) ) {
+ return false;
+ }
+ }
+ return apply_filters( 'woocommerce_shipping_' . $this->id . '_is_available', true, $package, $this );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/legacy-local-delivery/class-wc-shipping-legacy-local-delivery.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/legacy-local-delivery/class-wc-shipping-legacy-local-delivery.php
new file mode 100644
index 0000000..4484b79
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/legacy-local-delivery/class-wc-shipping-legacy-local-delivery.php
@@ -0,0 +1,181 @@
+id = 'legacy_local_delivery';
+ $this->method_title = __( 'Local delivery (legacy)', 'woocommerce' );
+ /* translators: %s: Admin shipping settings URL */
+ $this->method_description = '' . sprintf( __( 'This method is deprecated in 2.6.0 and will be removed in future versions - we recommend disabling it and instead setting up a new rate within your Shipping zones.', 'woocommerce' ), admin_url( 'admin.php?page=wc-settings&tab=shipping' ) ) . '';
+ $this->init();
+ }
+
+ /**
+ * Process and redirect if disabled.
+ */
+ public function process_admin_options() {
+ parent::process_admin_options();
+
+ if ( 'no' === $this->settings['enabled'] ) {
+ wp_redirect( admin_url( 'admin.php?page=wc-settings&tab=shipping§ion=options' ) );
+ exit;
+ }
+ }
+
+ /**
+ * Return the name of the option in the WP DB.
+ *
+ * @since 2.6.0
+ * @return string
+ */
+ public function get_option_key() {
+ return $this->plugin_id . 'local_delivery_settings';
+ }
+
+ /**
+ * Init function.
+ */
+ public function init() {
+
+ // Load the settings.
+ $this->init_form_fields();
+ $this->init_settings();
+
+ // Define user set variables.
+ $this->title = $this->get_option( 'title' );
+ $this->type = $this->get_option( 'type' );
+ $this->fee = $this->get_option( 'fee' );
+ $this->type = $this->get_option( 'type' );
+ $this->codes = $this->get_option( 'codes' );
+ $this->availability = $this->get_option( 'availability' );
+ $this->countries = $this->get_option( 'countries' );
+
+ add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
+ }
+
+ /**
+ * Calculate_shipping function.
+ *
+ * @param array $package (default: array()).
+ */
+ public function calculate_shipping( $package = array() ) {
+ $shipping_total = 0;
+
+ switch ( $this->type ) {
+ case 'fixed':
+ $shipping_total = $this->fee;
+ break;
+ case 'percent':
+ $shipping_total = $package['contents_cost'] * ( $this->fee / 100 );
+ break;
+ case 'product':
+ foreach ( $package['contents'] as $item_id => $values ) {
+ if ( $values['quantity'] > 0 && $values['data']->needs_shipping() ) {
+ $shipping_total += $this->fee * $values['quantity'];
+ }
+ }
+ break;
+ }
+
+ $rate = array(
+ 'id' => $this->id,
+ 'label' => $this->title,
+ 'cost' => $shipping_total,
+ 'package' => $package,
+ );
+
+ $this->add_rate( $rate );
+ }
+
+ /**
+ * Init form fields.
+ */
+ public function init_form_fields() {
+ $this->form_fields = array(
+ 'enabled' => array(
+ 'title' => __( 'Enable', 'woocommerce' ),
+ 'type' => 'checkbox',
+ 'label' => __( 'Once disabled, this legacy method will no longer be available.', 'woocommerce' ),
+ 'default' => 'no',
+ ),
+ 'title' => array(
+ 'title' => __( 'Title', 'woocommerce' ),
+ 'type' => 'text',
+ 'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce' ),
+ 'default' => __( 'Local delivery', 'woocommerce' ),
+ 'desc_tip' => true,
+ ),
+ 'type' => array(
+ 'title' => __( 'Fee type', 'woocommerce' ),
+ 'type' => 'select',
+ 'class' => 'wc-enhanced-select',
+ 'description' => __( 'How to calculate delivery charges', 'woocommerce' ),
+ 'default' => 'fixed',
+ 'options' => array(
+ 'fixed' => __( 'Fixed amount', 'woocommerce' ),
+ 'percent' => __( 'Percentage of cart total', 'woocommerce' ),
+ 'product' => __( 'Fixed amount per product', 'woocommerce' ),
+ ),
+ 'desc_tip' => true,
+ ),
+ 'fee' => array(
+ 'title' => __( 'Delivery fee', 'woocommerce' ),
+ 'type' => 'price',
+ 'description' => __( 'What fee do you want to charge for local delivery, disregarded if you choose free. Leave blank to disable.', 'woocommerce' ),
+ 'default' => '',
+ 'desc_tip' => true,
+ 'placeholder' => wc_format_localized_price( 0 ),
+ ),
+ 'codes' => array(
+ 'title' => __( 'Allowed ZIP/post codes', 'woocommerce' ),
+ 'type' => 'text',
+ 'desc_tip' => __( 'What ZIP/post codes are available for local delivery?', 'woocommerce' ),
+ 'default' => '',
+ 'description' => __( 'Separate codes with a comma. Accepts wildcards, e.g. P*
will match a postcode of PE30. Also accepts a pattern, e.g. NG1___
would match NG1 1AA but not NG10 1AA', 'woocommerce' ),
+ 'placeholder' => 'e.g. 12345, 56789',
+ ),
+ 'availability' => array(
+ 'title' => __( 'Method availability', 'woocommerce' ),
+ 'type' => 'select',
+ 'default' => 'all',
+ 'class' => 'availability wc-enhanced-select',
+ 'options' => array(
+ 'all' => __( 'All allowed countries', 'woocommerce' ),
+ 'specific' => __( 'Specific Countries', 'woocommerce' ),
+ ),
+ ),
+ 'countries' => array(
+ 'title' => __( 'Specific countries', 'woocommerce' ),
+ 'type' => 'multiselect',
+ 'class' => 'wc-enhanced-select',
+ 'css' => 'width: 400px;',
+ 'default' => '',
+ 'options' => WC()->countries->get_shipping_countries(),
+ 'custom_attributes' => array(
+ 'data-placeholder' => __( 'Select some countries', 'woocommerce' ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/legacy-local-pickup/class-wc-shipping-legacy-local-pickup.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/legacy-local-pickup/class-wc-shipping-legacy-local-pickup.php
new file mode 100644
index 0000000..dc0608e
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/legacy-local-pickup/class-wc-shipping-legacy-local-pickup.php
@@ -0,0 +1,232 @@
+id = 'legacy_local_pickup';
+ $this->method_title = __( 'Local pickup (legacy)', 'woocommerce' );
+ /* translators: %s: Admin shipping settings URL */
+ $this->method_description = '' . sprintf( __( 'This method is deprecated in 2.6.0 and will be removed in future versions - we recommend disabling it and instead setting up a new rate within your Shipping zones.', 'woocommerce' ), admin_url( 'admin.php?page=wc-settings&tab=shipping' ) ) . '';
+ $this->init();
+ }
+
+ /**
+ * Process and redirect if disabled.
+ */
+ public function process_admin_options() {
+ parent::process_admin_options();
+
+ if ( 'no' === $this->settings['enabled'] ) {
+ wp_redirect( admin_url( 'admin.php?page=wc-settings&tab=shipping§ion=options' ) );
+ exit;
+ }
+ }
+
+ /**
+ * Return the name of the option in the WP DB.
+ *
+ * @since 2.6.0
+ * @return string
+ */
+ public function get_option_key() {
+ return $this->plugin_id . 'local_pickup_settings';
+ }
+
+ /**
+ * Init function.
+ */
+ public function init() {
+
+ // Load the settings.
+ $this->init_form_fields();
+ $this->init_settings();
+
+ // Define user set variables.
+ $this->enabled = $this->get_option( 'enabled' );
+ $this->title = $this->get_option( 'title' );
+ $this->codes = $this->get_option( 'codes' );
+ $this->availability = $this->get_option( 'availability' );
+ $this->countries = $this->get_option( 'countries' );
+
+ // Actions.
+ add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
+ }
+
+ /**
+ * Calculate shipping.
+ *
+ * @param array $package Package information.
+ */
+ public function calculate_shipping( $package = array() ) {
+ $rate = array(
+ 'id' => $this->id,
+ 'label' => $this->title,
+ 'package' => $package,
+ );
+ $this->add_rate( $rate );
+ }
+
+ /**
+ * Initialize form fields.
+ */
+ public function init_form_fields() {
+ $this->form_fields = array(
+ 'enabled' => array(
+ 'title' => __( 'Enable', 'woocommerce' ),
+ 'type' => 'checkbox',
+ 'label' => __( 'Once disabled, this legacy method will no longer be available.', 'woocommerce' ),
+ 'default' => 'no',
+ ),
+ 'title' => array(
+ 'title' => __( 'Title', 'woocommerce' ),
+ 'type' => 'text',
+ 'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce' ),
+ 'default' => __( 'Local pickup', 'woocommerce' ),
+ 'desc_tip' => true,
+ ),
+ 'codes' => array(
+ 'title' => __( 'Allowed ZIP/post codes', 'woocommerce' ),
+ 'type' => 'text',
+ 'desc_tip' => __( 'What ZIP/post codes are available for local pickup?', 'woocommerce' ),
+ 'default' => '',
+ 'description' => __( 'Separate codes with a comma. Accepts wildcards, e.g. P*
will match a postcode of PE30. Also accepts a pattern, e.g. NG1___
would match NG1 1AA but not NG10 1AA', 'woocommerce' ),
+ 'placeholder' => 'e.g. 12345, 56789',
+ ),
+ 'availability' => array(
+ 'title' => __( 'Method availability', 'woocommerce' ),
+ 'type' => 'select',
+ 'default' => 'all',
+ 'class' => 'availability wc-enhanced-select',
+ 'options' => array(
+ 'all' => __( 'All allowed countries', 'woocommerce' ),
+ 'specific' => __( 'Specific countries', 'woocommerce' ),
+ ),
+ ),
+ 'countries' => array(
+ 'title' => __( 'Specific countries', 'woocommerce' ),
+ 'type' => 'multiselect',
+ 'class' => 'wc-enhanced-select',
+ 'css' => 'width: 400px;',
+ 'default' => '',
+ 'options' => WC()->countries->get_shipping_countries(),
+ 'custom_attributes' => array(
+ 'data-placeholder' => __( 'Select some countries', 'woocommerce' ),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * Get postcodes for this method.
+ *
+ * @return array
+ */
+ public function get_valid_postcodes() {
+ $codes = array();
+
+ if ( '' !== $this->codes ) {
+ foreach ( explode( ',', $this->codes ) as $code ) {
+ $codes[] = strtoupper( trim( $code ) );
+ }
+ }
+
+ return $codes;
+ }
+
+ /**
+ * See if a given postcode matches valid postcodes.
+ *
+ * @param string $postcode Postcode to check.
+ * @param string $country code Code of the country to check postcode against.
+ * @return boolean
+ */
+ public function is_valid_postcode( $postcode, $country ) {
+ $codes = $this->get_valid_postcodes();
+ $postcode = $this->clean( $postcode );
+ $formatted_postcode = wc_format_postcode( $postcode, $country );
+
+ if ( in_array( $postcode, $codes, true ) || in_array( $formatted_postcode, $codes, true ) ) {
+ return true;
+ }
+
+ // Pattern matching.
+ foreach ( $codes as $c ) {
+ $pattern = '/^' . str_replace( '_', '[0-9a-zA-Z]', preg_quote( $c ) ) . '$/i';
+ if ( preg_match( $pattern, $postcode ) ) {
+ return true;
+ }
+ }
+
+ // Wildcard search.
+ $wildcard_postcode = $formatted_postcode . '*';
+ $postcode_length = strlen( $formatted_postcode );
+
+ for ( $i = 0; $i < $postcode_length; $i++ ) {
+ if ( in_array( $wildcard_postcode, $codes, true ) ) {
+ return true;
+ }
+ $wildcard_postcode = substr( $wildcard_postcode, 0, -2 ) . '*';
+ }
+
+ return false;
+ }
+
+ /**
+ * See if the method is available.
+ *
+ * @param array $package Package information.
+ * @return bool
+ */
+ public function is_available( $package ) {
+ $is_available = 'yes' === $this->enabled;
+
+ if ( $is_available && $this->get_valid_postcodes() ) {
+ $is_available = $this->is_valid_postcode( $package['destination']['postcode'], $package['destination']['country'] );
+ }
+
+ if ( $is_available ) {
+ if ( 'specific' === $this->availability ) {
+ $ship_to_countries = $this->countries;
+ } else {
+ $ship_to_countries = array_keys( WC()->countries->get_shipping_countries() );
+ }
+ if ( is_array( $ship_to_countries ) && ! in_array( $package['destination']['country'], $ship_to_countries, true ) ) {
+ $is_available = false;
+ }
+ }
+
+ return apply_filters( 'woocommerce_shipping_' . $this->id . '_is_available', $is_available, $package, $this );
+ }
+
+ /**
+ * Clean function.
+ *
+ * @access public
+ * @param mixed $code Code.
+ * @return string
+ */
+ public function clean( $code ) {
+ return str_replace( '-', '', sanitize_title( $code ) ) . ( strstr( $code, '*' ) ? '*' : '' );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/local-pickup/class-wc-shipping-local-pickup.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/local-pickup/class-wc-shipping-local-pickup.php
new file mode 100644
index 0000000..a64c699
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shipping/local-pickup/class-wc-shipping-local-pickup.php
@@ -0,0 +1,106 @@
+id = 'local_pickup';
+ $this->instance_id = absint( $instance_id );
+ $this->method_title = __( 'Local pickup', 'woocommerce' );
+ $this->method_description = __( 'Allow customers to pick up orders themselves. By default, when using local pickup store base taxes will apply regardless of customer address.', 'woocommerce' );
+ $this->supports = array(
+ 'shipping-zones',
+ 'instance-settings',
+ 'instance-settings-modal',
+ );
+ $this->init();
+ }
+
+ /**
+ * Initialize local pickup.
+ */
+ public function init() {
+
+ // Load the settings.
+ $this->init_form_fields();
+ $this->init_settings();
+
+ // Define user set variables.
+ $this->title = $this->get_option( 'title' );
+ $this->tax_status = $this->get_option( 'tax_status' );
+ $this->cost = $this->get_option( 'cost' );
+
+ // Actions.
+ add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
+ }
+
+ /**
+ * Calculate local pickup shipping.
+ *
+ * @param array $package Package information.
+ */
+ public function calculate_shipping( $package = array() ) {
+ $this->add_rate(
+ array(
+ 'label' => $this->title,
+ 'package' => $package,
+ 'cost' => $this->cost,
+ )
+ );
+ }
+
+ /**
+ * Init form fields.
+ */
+ public function init_form_fields() {
+ $this->instance_form_fields = array(
+ 'title' => array(
+ 'title' => __( 'Title', 'woocommerce' ),
+ 'type' => 'text',
+ 'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce' ),
+ 'default' => __( 'Local pickup', 'woocommerce' ),
+ 'desc_tip' => true,
+ ),
+ 'tax_status' => array(
+ 'title' => __( 'Tax status', 'woocommerce' ),
+ 'type' => 'select',
+ 'class' => 'wc-enhanced-select',
+ 'default' => 'taxable',
+ 'options' => array(
+ 'taxable' => __( 'Taxable', 'woocommerce' ),
+ 'none' => _x( 'None', 'Tax status', 'woocommerce' ),
+ ),
+ ),
+ 'cost' => array(
+ 'title' => __( 'Cost', 'woocommerce' ),
+ 'type' => 'text',
+ 'placeholder' => '0',
+ 'description' => __( 'Optional cost for local pickup.', 'woocommerce' ),
+ 'default' => '',
+ 'desc_tip' => true,
+ ),
+ );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-cart.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-cart.php
new file mode 100644
index 0000000..3784fb7
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-cart.php
@@ -0,0 +1,102 @@
+shipping()->reset_shipping();
+
+ $address = array();
+
+ $address['country'] = isset( $_POST['calc_shipping_country'] ) ? wc_clean( wp_unslash( $_POST['calc_shipping_country'] ) ) : ''; // WPCS: input var ok, CSRF ok, sanitization ok.
+ $address['state'] = isset( $_POST['calc_shipping_state'] ) ? wc_clean( wp_unslash( $_POST['calc_shipping_state'] ) ) : ''; // WPCS: input var ok, CSRF ok, sanitization ok.
+ $address['postcode'] = isset( $_POST['calc_shipping_postcode'] ) ? wc_clean( wp_unslash( $_POST['calc_shipping_postcode'] ) ) : ''; // WPCS: input var ok, CSRF ok, sanitization ok.
+ $address['city'] = isset( $_POST['calc_shipping_city'] ) ? wc_clean( wp_unslash( $_POST['calc_shipping_city'] ) ) : ''; // WPCS: input var ok, CSRF ok, sanitization ok.
+
+ $address = apply_filters( 'woocommerce_cart_calculate_shipping_address', $address );
+
+ if ( $address['postcode'] && ! WC_Validation::is_postcode( $address['postcode'], $address['country'] ) ) {
+ throw new Exception( __( 'Please enter a valid postcode / ZIP.', 'woocommerce' ) );
+ } elseif ( $address['postcode'] ) {
+ $address['postcode'] = wc_format_postcode( $address['postcode'], $address['country'] );
+ }
+
+ if ( $address['country'] ) {
+ if ( ! WC()->customer->get_billing_first_name() ) {
+ WC()->customer->set_billing_location( $address['country'], $address['state'], $address['postcode'], $address['city'] );
+ }
+ WC()->customer->set_shipping_location( $address['country'], $address['state'], $address['postcode'], $address['city'] );
+ } else {
+ WC()->customer->set_billing_address_to_base();
+ WC()->customer->set_shipping_address_to_base();
+ }
+
+ WC()->customer->set_calculated_shipping( true );
+ WC()->customer->save();
+
+ wc_add_notice( __( 'Shipping costs updated.', 'woocommerce' ), 'notice' );
+
+ do_action( 'woocommerce_calculated_shipping' );
+
+ } catch ( Exception $e ) {
+ if ( ! empty( $e ) ) {
+ wc_add_notice( $e->getMessage(), 'error' );
+ }
+ }
+ }
+
+ /**
+ * Output the cart shortcode.
+ *
+ * @param array $atts Shortcode attributes.
+ */
+ public static function output( $atts ) {
+ if ( ! apply_filters( 'woocommerce_output_cart_shortcode_content', true ) ) {
+ return;
+ }
+
+ // Constants.
+ wc_maybe_define_constant( 'WOOCOMMERCE_CART', true );
+
+ $atts = shortcode_atts( array(), $atts, 'woocommerce_cart' );
+ $nonce_value = wc_get_var( $_REQUEST['woocommerce-shipping-calculator-nonce'], wc_get_var( $_REQUEST['_wpnonce'], '' ) ); // @codingStandardsIgnoreLine.
+
+ // Update Shipping. Nonce check uses new value and old value (woocommerce-cart). @todo remove in 4.0.
+ if ( ! empty( $_POST['calc_shipping'] ) && ( wp_verify_nonce( $nonce_value, 'woocommerce-shipping-calculator' ) || wp_verify_nonce( $nonce_value, 'woocommerce-cart' ) ) ) { // WPCS: input var ok.
+ self::calculate_shipping();
+
+ // Also calc totals before we check items so subtotals etc are up to date.
+ WC()->cart->calculate_totals();
+ }
+
+ // Check cart items are valid.
+ do_action( 'woocommerce_check_cart_items' );
+
+ // Calc totals.
+ WC()->cart->calculate_totals();
+
+ if ( WC()->cart->is_empty() ) {
+ wc_get_template( 'cart/cart-empty.php' );
+ } else {
+ wc_get_template( 'cart/cart.php' );
+ }
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-checkout.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-checkout.php
new file mode 100644
index 0000000..4f6450e
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-checkout.php
@@ -0,0 +1,297 @@
+cart ) ) {
+ return;
+ }
+
+ // Backwards compatibility with old pay and thanks link arguments.
+ if ( isset( $_GET['order'] ) && isset( $_GET['key'] ) ) { // WPCS: input var ok, CSRF ok.
+ wc_deprecated_argument( __CLASS__ . '->' . __FUNCTION__, '2.1', '"order" is no longer used to pass an order ID. Use the order-pay or order-received endpoint instead.' );
+
+ // Get the order to work out what we are showing.
+ $order_id = absint( $_GET['order'] ); // WPCS: input var ok.
+ $order = wc_get_order( $order_id );
+
+ if ( $order && $order->has_status( 'pending' ) ) {
+ $wp->query_vars['order-pay'] = absint( $_GET['order'] ); // WPCS: input var ok.
+ } else {
+ $wp->query_vars['order-received'] = absint( $_GET['order'] ); // WPCS: input var ok.
+ }
+ }
+
+ // Handle checkout actions.
+ if ( ! empty( $wp->query_vars['order-pay'] ) ) {
+
+ self::order_pay( $wp->query_vars['order-pay'] );
+
+ } elseif ( isset( $wp->query_vars['order-received'] ) ) {
+
+ self::order_received( $wp->query_vars['order-received'] );
+
+ } else {
+
+ self::checkout();
+
+ }
+ }
+
+ /**
+ * Show the pay page.
+ *
+ * @throws Exception When validate fails.
+ * @param int $order_id Order ID.
+ */
+ private static function order_pay( $order_id ) {
+
+ do_action( 'before_woocommerce_pay' );
+
+ $order_id = absint( $order_id );
+
+ // Pay for existing order.
+ if ( isset( $_GET['pay_for_order'], $_GET['key'] ) && $order_id ) { // WPCS: input var ok, CSRF ok.
+ try {
+ $order_key = isset( $_GET['key'] ) ? wc_clean( wp_unslash( $_GET['key'] ) ) : ''; // WPCS: input var ok, CSRF ok.
+ $order = wc_get_order( $order_id );
+
+ // Order or payment link is invalid.
+ if ( ! $order || $order->get_id() !== $order_id || ! hash_equals( $order->get_order_key(), $order_key ) ) {
+ throw new Exception( __( 'Sorry, this order is invalid and cannot be paid for.', 'woocommerce' ) );
+ }
+
+ // Logged out customer does not have permission to pay for this order.
+ if ( ! current_user_can( 'pay_for_order', $order_id ) && ! is_user_logged_in() ) {
+ echo '';
+ }
+
+ $this->events = array();
+ }
+
+ /**
+ * Fire off API calls for events that weren't converted to pixels.
+ *
+ * This handles wp_redirect().
+ */
+ public function send_tracks_requests() {
+ if ( empty( $this->events ) ) {
+ return;
+ }
+
+ foreach ( $this->events as $event ) {
+ WC_Tracks_Client::record_event( $event );
+ }
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/class-wc-tracks.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/class-wc-tracks.php
new file mode 100644
index 0000000..565ef7c
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/class-wc-tracks.php
@@ -0,0 +1,115 @@
+ home_url(),
+ 'blog_lang' => get_user_locale( $user_id ),
+ 'blog_id' => class_exists( 'Jetpack_Options' ) ? Jetpack_Options::get_option( 'id' ) : null,
+ 'products_count' => self::get_products_count(),
+ );
+ set_transient( 'wc_tracks_blog_details', $blog_details, DAY_IN_SECONDS );
+ }
+ return $blog_details;
+ }
+
+ /**
+ * Gather details from the request to the server.
+ *
+ * @return array Server details.
+ */
+ public static function get_server_details() {
+ $data = array();
+
+ $data['_via_ua'] = isset( $_SERVER['HTTP_USER_AGENT'] ) ? wc_clean( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '';
+ $data['_via_ip'] = isset( $_SERVER['REMOTE_ADDR'] ) ? wc_clean( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '';
+ $data['_lg'] = isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ? wc_clean( wp_unslash( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) : '';
+ $data['_dr'] = isset( $_SERVER['HTTP_REFERER'] ) ? wc_clean( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) : '';
+
+ $uri = isset( $_SERVER['REQUEST_URI'] ) ? wc_clean( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';
+ $host = isset( $_SERVER['HTTP_HOST'] ) ? wc_clean( wp_unslash( $_SERVER['HTTP_HOST'] ) ) : '';
+ $data['_dl'] = isset( $_SERVER['REQUEST_SCHEME'] ) ? wc_clean( wp_unslash( $_SERVER['REQUEST_SCHEME'] ) ) . '://' . $host . $uri : '';
+
+ return $data;
+ }
+
+ /**
+ * Record an event in Tracks - this is the preferred way to record events from PHP.
+ *
+ * @param string $event_name The name of the event.
+ * @param array $properties Custom properties to send with the event.
+ * @return bool|WP_Error True for success or WP_Error if the event pixel could not be fired.
+ */
+ public static function record_event( $event_name, $properties = array() ) {
+ /**
+ * Don't track users who don't have tracking enabled.
+ */
+ if ( ! WC_Site_Tracking::is_tracking_enabled() ) {
+ return false;
+ }
+
+ $user = wp_get_current_user();
+
+ // We don't want to track user events during unit tests/CI runs.
+ if ( $user instanceof WP_User && 'wptests_capabilities' === $user->cap_key ) {
+ return false;
+ }
+ $prefixed_event_name = self::PREFIX . $event_name;
+
+ $data = array(
+ '_en' => $prefixed_event_name,
+ '_ts' => WC_Tracks_Client::build_timestamp(),
+ );
+
+ $server_details = self::get_server_details();
+ $identity = WC_Tracks_Client::get_identity( $user->ID );
+ $blog_details = self::get_blog_details( $user->ID );
+
+ // Allow event props to be filtered to enable adding site-wide props.
+ $filtered_properties = apply_filters( 'woocommerce_tracks_event_properties', $properties, $prefixed_event_name );
+
+ // Delete _ui and _ut protected properties.
+ unset( $filtered_properties['_ui'] );
+ unset( $filtered_properties['_ut'] );
+
+ $event_obj = new WC_Tracks_Event( array_merge( $data, $server_details, $identity, $blog_details, $filtered_properties ) );
+
+ if ( is_wp_error( $event_obj->error ) ) {
+ return $event_obj->error;
+ }
+
+ return $event_obj->record();
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-admin-setup-wizard-tracking.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-admin-setup-wizard-tracking.php
new file mode 100644
index 0000000..158904c
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-admin-setup-wizard-tracking.php
@@ -0,0 +1,176 @@
+queue as $script ) {
+ if ( in_array( $script, $allowed, true ) ) {
+ continue;
+ }
+ wp_dequeue_script( $script );
+ }
+ }
+
+ /**
+ * Track when tracking is opted into and OBW has started.
+ *
+ * @param string $option Option name.
+ * @param string $value Option value.
+ *
+ * @deprecated 4.6.0
+ */
+ public function track_start( $option, $value ) {
+ _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
+ }
+
+ /**
+ * Track the marketing form on submit.
+ *
+ * @deprecated 4.6.0
+ */
+ public function track_ready_next_steps() {
+ _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
+ }
+
+ /**
+ * Track various events when a step is saved.
+ *
+ * @deprecated 4.6.0
+ */
+ public function add_step_save_events() {
+ _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
+ }
+
+ /**
+ * Track store setup and store properties on save.
+ *
+ * @deprecated 4.6.0
+ */
+ public function track_store_setup() {
+ _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
+ }
+
+ /**
+ * Track payment gateways selected.
+ *
+ * @deprecated 4.6.0
+ */
+ public function track_payments() {
+ _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
+ }
+
+ /**
+ * Track shipping units and whether or not labels are set.
+ *
+ * @deprecated 4.6.0
+ */
+ public function track_shipping() {
+ _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
+ }
+
+ /**
+ * Track recommended plugins selected for install.
+ *
+ * @deprecated 4.6.0
+ */
+ public function track_recommended() {
+ _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
+ }
+
+ /**
+ * Tracks when Jetpack is activated through the OBW.
+ *
+ * @deprecated 4.6.0
+ */
+ public function track_jetpack_activate() {
+ _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
+ }
+
+ /**
+ * Tracks when last next_steps screen is viewed in the OBW.
+ *
+ * @deprecated 4.6.0
+ */
+ public function track_next_steps() {
+ _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
+ }
+
+ /**
+ * Track skipped steps.
+ *
+ * @deprecated 4.6.0
+ */
+ public function track_skip_step() {
+ _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
+ }
+
+ /**
+ * Set the OBW steps inside this class instance.
+ *
+ * @param array $steps Array of OBW steps.
+ *
+ * @deprecated 4.6.0
+ */
+ public function set_obw_steps( $steps ) {
+ _deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
+ $this->steps = $steps;
+
+ return $steps;
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-coupon-tracking.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-coupon-tracking.php
new file mode 100644
index 0000000..c5faffa
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-coupon-tracking.php
@@ -0,0 +1,39 @@
+ $coupon->get_code(),
+ 'free_shipping' => $coupon->get_free_shipping(),
+ 'individual_use' => $coupon->get_individual_use(),
+ 'exclude_sale_items' => $coupon->get_exclude_sale_items(),
+ 'usage_limits_applied' => 0 < intval( $coupon->get_usage_limit() )
+ || 0 < intval( $coupon->get_usage_limit_per_user() )
+ || 0 < intval( $coupon->get_limit_usage_to_x_items() ),
+ );
+
+ WC_Tracks::record_event( 'coupon_updated', $properties );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-coupons-tracking.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-coupons-tracking.php
new file mode 100644
index 0000000..cc32e40
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-coupons-tracking.php
@@ -0,0 +1,73 @@
+tracks_coupons_bulk_actions();
+
+ WC_Tracks::record_event(
+ 'coupons_view',
+ array(
+ 'status' => isset( $_GET['post_status'] ) ? sanitize_text_field( wp_unslash( $_GET['post_status'] ) ) : 'all',
+ )
+ );
+
+ if ( isset( $_GET['filter_action'] ) && 'Filter' === sanitize_text_field( wp_unslash( $_GET['filter_action'] ) ) && isset( $_GET['coupon_type'] ) ) {
+ WC_Tracks::record_event(
+ 'coupons_filter',
+ array(
+ 'filter' => 'coupon_type',
+ 'value' => sanitize_text_field( wp_unslash( $_GET['coupon_type'] ) ),
+ )
+ );
+ }
+
+ if ( isset( $_GET['s'] ) && 0 < strlen( sanitize_text_field( wp_unslash( $_GET['s'] ) ) ) ) {
+ WC_Tracks::record_event( 'coupons_search' );
+ }
+ }
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-extensions-tracking.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-extensions-tracking.php
new file mode 100644
index 0000000..70f582b
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-extensions-tracking.php
@@ -0,0 +1,79 @@
+ empty( $_REQUEST['section'] ) ? '_featured' : wc_clean( wp_unslash( $_REQUEST['section'] ) ),
+ );
+
+ if ( ! empty( $_REQUEST['search'] ) ) {
+ $event = 'extensions_view_search';
+ $properties['search_term'] = wc_clean( wp_unslash( $_REQUEST['search'] ) );
+ }
+ // phpcs:enable
+
+ WC_Tracks::record_event( $event, $properties );
+ }
+
+ /**
+ * Send a Tracks even when a Helper connection process is initiated.
+ */
+ public function track_helper_connection_start() {
+ WC_Tracks::record_event( 'extensions_subscriptions_connect' );
+ }
+
+ /**
+ * Send a Tracks even when a Helper connection process is cancelled.
+ */
+ public function track_helper_connection_cancelled() {
+ WC_Tracks::record_event( 'extensions_subscriptions_cancelled' );
+ }
+
+ /**
+ * Send a Tracks even when a Helper connection process completed successfully.
+ */
+ public function track_helper_connection_complete() {
+ WC_Tracks::record_event( 'extensions_subscriptions_connected' );
+ }
+
+ /**
+ * Send a Tracks even when a Helper has been disconnected.
+ */
+ public function track_helper_disconnected() {
+ WC_Tracks::record_event( 'extensions_subscriptions_disconnect' );
+ }
+
+ /**
+ * Send a Tracks even when Helper subscriptions are refreshed.
+ */
+ public function track_helper_subscriptions_refresh() {
+ WC_Tracks::record_event( 'extensions_subscriptions_update' );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-importer-tracking.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-importer-tracking.php
new file mode 100644
index 0000000..648424c
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-importer-tracking.php
@@ -0,0 +1,83 @@
+track_product_importer_start();
+ }
+
+ if ( 'done' === $_REQUEST['step'] ) {
+ return $this->track_product_importer_complete();
+ }
+ // phpcs:enable
+ }
+
+ /**
+ * Send a Tracks event when the product importer is started.
+ *
+ * @return void
+ */
+ public function track_product_importer_start() {
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended
+ if ( ! isset( $_REQUEST['file'] ) || ! isset( $_REQUEST['_wpnonce'] ) ) {
+ return;
+ }
+
+ $properties = array(
+ 'update_existing' => isset( $_REQUEST['update_existing'] ) ? (bool) $_REQUEST['update_existing'] : false,
+ 'delimiter' => empty( $_REQUEST['delimiter'] ) ? ',' : wc_clean( wp_unslash( $_REQUEST['delimiter'] ) ),
+ );
+ // phpcs:enable
+
+ WC_Tracks::record_event( 'product_import_start', $properties );
+ }
+
+ /**
+ * Send a Tracks event when the product importer has finished.
+ *
+ * @return void
+ */
+ public function track_product_importer_complete() {
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended
+ if ( ! isset( $_REQUEST['nonce'] ) ) {
+ return;
+ }
+
+ $properties = array(
+ 'imported' => isset( $_GET['products-imported'] ) ? absint( $_GET['products-imported'] ) : 0,
+ 'updated' => isset( $_GET['products-updated'] ) ? absint( $_GET['products-updated'] ) : 0,
+ 'failed' => isset( $_GET['products-failed'] ) ? absint( $_GET['products-failed'] ) : 0,
+ 'skipped' => isset( $_GET['products-skipped'] ) ? absint( $_GET['products-skipped'] ) : 0,
+ );
+ // phpcs:enable
+
+ WC_Tracks::record_event( 'product_import_complete', $properties );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-order-tracking.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-order-tracking.php
new file mode 100644
index 0000000..9035cb2
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-order-tracking.php
@@ -0,0 +1,40 @@
+get_id() ) {
+ return;
+ }
+ $properties = array(
+ 'current_status' => $order->get_status(),
+ 'date_created' => $order->get_date_created() ? $order->get_date_created()->format( DateTime::ATOM ) : '',
+ 'payment_method' => $order->get_payment_method(),
+ );
+
+ WC_Tracks::record_event( 'single_order_view', $properties );
+ }
+}
+
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-orders-tracking.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-orders-tracking.php
new file mode 100644
index 0000000..a889074
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-orders-tracking.php
@@ -0,0 +1,178 @@
+id ) {
+ // we are on the order listing page, and query results are being shown.
+ WC_Tracks::record_event( 'orders_view_search' );
+ }
+
+ return $order_ids;
+ }
+
+ /**
+ * Send a Tracks event when the Orders page is viewed.
+ */
+ public function track_orders_view() {
+ if ( isset( $_GET['post_type'] ) && 'shop_order' === wp_unslash( $_GET['post_type'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
+
+ // phpcs:disable WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput
+ $properties = array(
+ 'status' => isset( $_GET['post_status'] ) ? sanitize_text_field( $_GET['post_status'] ) : 'all',
+ );
+ // phpcs:enable
+
+ WC_Tracks::record_event( 'orders_view', $properties );
+ }
+ }
+
+ /**
+ * Send a Tracks event when an order status is changed.
+ *
+ * @param int $id Order id.
+ * @param string $previous_status the old WooCommerce order status.
+ * @param string $next_status the new WooCommerce order status.
+ */
+ public function track_order_status_change( $id, $previous_status, $next_status ) {
+ $order = wc_get_order( $id );
+
+ $properties = array(
+ 'order_id' => $id,
+ 'next_status' => $next_status,
+ 'previous_status' => $previous_status,
+ 'date_created' => $order->get_date_created() ? $order->get_date_created()->date( 'Y-m-d' ) : '',
+ 'payment_method' => $order->get_payment_method(),
+ 'order_total' => $order->get_total(),
+ );
+
+ WC_Tracks::record_event( 'orders_edit_status_change', $properties );
+ }
+
+ /**
+ * Send a Tracks event when an order date is changed.
+ *
+ * @param int $id Order id.
+ */
+ public function track_created_date_change( $id ) {
+ $post_type = get_post_type( $id );
+
+ if ( 'shop_order' !== $post_type ) {
+ return;
+ }
+
+ if ( 'auto-draft' === get_post_status( $id ) ) {
+ return;
+ }
+
+ $order = wc_get_order( $id );
+ $date_created = $order->get_date_created() ? $order->get_date_created()->date( 'Y-m-d H:i:s' ) : '';
+ // phpcs:disable WordPress.Security.NonceVerification
+ $new_date = sprintf(
+ '%s %2d:%2d:%2d',
+ isset( $_POST['order_date'] ) ? wc_clean( wp_unslash( $_POST['order_date'] ) ) : '',
+ isset( $_POST['order_date_hour'] ) ? wc_clean( wp_unslash( $_POST['order_date_hour'] ) ) : '',
+ isset( $_POST['order_date_minute'] ) ? wc_clean( wp_unslash( $_POST['order_date_minute'] ) ) : '',
+ isset( $_POST['order_date_second'] ) ? wc_clean( wp_unslash( $_POST['order_date_second'] ) ) : ''
+ );
+ // phpcs:enable
+
+ if ( $new_date !== $date_created ) {
+ $properties = array(
+ 'order_id' => $id,
+ 'status' => $order->get_status(),
+ );
+
+ WC_Tracks::record_event( 'order_edit_date_created', $properties );
+ }
+ }
+
+ /**
+ * Track order actions taken.
+ *
+ * @param int $order_id Order ID.
+ */
+ public function track_order_action( $order_id ) {
+ // phpcs:disable WordPress.Security.NonceVerification
+ if ( ! empty( $_POST['wc_order_action'] ) ) {
+ $order = wc_get_order( $order_id );
+ $action = wc_clean( wp_unslash( $_POST['wc_order_action'] ) );
+ $properties = array(
+ 'order_id' => $order_id,
+ 'status' => $order->get_status(),
+ 'action' => $action,
+ );
+
+ WC_Tracks::record_event( 'order_edit_order_action', $properties );
+ }
+ // phpcs:enable
+ }
+
+ /**
+ * Track "add order" button on the Edit Order screen.
+ */
+ public function track_add_order_from_edit() {
+ // phpcs:ignore WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
+ if ( isset( $_GET['post_type'] ) && 'shop_order' === wp_unslash( $_GET['post_type'] ) ) {
+ $referer = wp_get_referer();
+
+ if ( $referer ) {
+ $referring_page = wp_parse_url( $referer );
+ $referring_args = array();
+ $post_edit_page = wp_parse_url( admin_url( 'post.php' ) );
+
+ if ( ! empty( $referring_page['query'] ) ) {
+ parse_str( $referring_page['query'], $referring_args );
+ }
+
+ // Determine if we arrived from an Order Edit screen.
+ if (
+ $post_edit_page['path'] === $referring_page['path'] &&
+ isset( $referring_args['action'] ) &&
+ 'edit' === $referring_args['action'] &&
+ isset( $referring_args['post'] ) &&
+ 'shop_order' === get_post_type( $referring_args['post'] )
+ ) {
+ WC_Tracks::record_event( 'order_edit_add_order' );
+ }
+ }
+ }
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-products-tracking.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-products-tracking.php
new file mode 100644
index 0000000..577e1d5
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-products-tracking.php
@@ -0,0 +1,211 @@
+post_type ) {
+ return;
+ }
+
+ $properties = array(
+ 'product_id' => $product_id,
+ );
+
+ WC_Tracks::record_event( 'product_edit', $properties );
+ }
+
+ /**
+ * Track the Update button being clicked on the client side.
+ * This is needed because `track_product_updated` (using the `edit_post`
+ * hook) is called in response to a number of other triggers.
+ *
+ * @param WP_Post $post The post, not used.
+ */
+ public function track_product_updated_client_side( $post ) {
+ wc_enqueue_js(
+ "
+ if ( $( 'h1.wp-heading-inline' ).text().trim() === '" . __( 'Edit product', 'woocommerce' ) . "') {
+ var initialStockValue = $( '#_stock' ).val();
+ var hasRecordedEvent = false;
+
+ $( '#publish' ).click( function() {
+ if ( hasRecordedEvent ) {
+ return;
+ }
+
+ var currentStockValue = $( '#_stock' ).val();
+ var properties = {
+ product_type: $( '#product-type' ).val(),
+ is_virtual: $( '#_virtual' ).is( ':checked' ) ? 'Y' : 'N',
+ is_downloadable: $( '#_downloadable' ).is( ':checked' ) ? 'Y' : 'N',
+ manage_stock: $( '#_manage_stock' ).is( ':checked' ) ? 'Y' : 'N',
+ stock_quantity_update: ( initialStockValue != currentStockValue ) ? 'Y' : 'N',
+ };
+
+ window.wcTracks.recordEvent( 'product_update', properties );
+ hasRecordedEvent = true;
+ } );
+ }
+ "
+ );
+ }
+
+ /**
+ * Send a Tracks event when a product is published.
+ *
+ * @param string $new_status New post_status.
+ * @param string $old_status Previous post_status.
+ * @param object $post WordPress post.
+ */
+ public function track_product_published( $new_status, $old_status, $post ) {
+ if (
+ 'product' !== $post->post_type ||
+ 'publish' !== $new_status ||
+ 'publish' === $old_status
+ ) {
+ return;
+ }
+
+ $properties = array(
+ 'product_id' => $post->ID,
+ );
+
+ WC_Tracks::record_event( 'product_add_publish', $properties );
+ }
+
+ /**
+ * Send a Tracks event when a product category is created.
+ *
+ * @param int $category_id Category ID.
+ */
+ public function track_product_category_created( $category_id ) {
+ // phpcs:disable WordPress.Security.NonceVerification.Missing
+ // Only track category creation from the edit product screen or the
+ // category management screen (which both occur via AJAX).
+ if (
+ ! Constants::is_defined( 'DOING_AJAX' ) ||
+ empty( $_POST['action'] ) ||
+ (
+ // Product Categories screen.
+ 'add-tag' !== $_POST['action'] &&
+ // Edit Product screen.
+ 'add-product_cat' !== $_POST['action']
+ )
+ ) {
+ return;
+ }
+
+ $category = get_term( $category_id, 'product_cat' );
+ $properties = array(
+ 'category_id' => $category_id,
+ 'parent_id' => $category->parent,
+ 'page' => ( 'add-tag' === $_POST['action'] ) ? 'categories' : 'product',
+ );
+ // phpcs:enable
+
+ WC_Tracks::record_event( 'product_category_add', $properties );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-settings-tracking.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-settings-tracking.php
new file mode 100644
index 0000000..c713db5
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-settings-tracking.php
@@ -0,0 +1,118 @@
+allowed_options[] = $option['id'];
+
+ // Delay attaching this action since it could get fired a lot.
+ if ( false === has_action( 'update_option', array( $this, 'track_setting_change' ) ) ) {
+ add_action( 'update_option', array( $this, 'track_setting_change' ), 10, 3 );
+ }
+ }
+
+ /**
+ * Add WooCommerce option to a list of updated options.
+ *
+ * @param string $option_name Option being updated.
+ * @param mixed $old_value Old value of option.
+ * @param mixed $new_value New value of option.
+ */
+ public function track_setting_change( $option_name, $old_value, $new_value ) {
+ // Make sure this is a WooCommerce option.
+ if ( ! in_array( $option_name, $this->allowed_options, true ) ) {
+ return;
+ }
+
+ // Check to make sure the new value is truly different.
+ // `woocommerce_price_num_decimals` tends to trigger this
+ // because form values aren't coerced (e.g. '2' vs. 2).
+ if (
+ is_scalar( $old_value ) &&
+ is_scalar( $new_value ) &&
+ (string) $old_value === (string) $new_value
+ ) {
+ return;
+ }
+
+ $this->updated_options[] = $option_name;
+ }
+
+ /**
+ * Send a Tracks event for WooCommerce options that changed values.
+ */
+ public function send_settings_change_event() {
+ global $current_tab;
+
+ if ( empty( $this->updated_options ) ) {
+ return;
+ }
+
+ $properties = array(
+ 'settings' => implode( ',', $this->updated_options ),
+ );
+
+ if ( isset( $current_tab ) ) {
+ $properties['tab'] = $current_tab;
+ }
+
+ WC_Tracks::record_event( 'settings_change', $properties );
+ }
+
+ /**
+ * Send a Tracks event for WooCommerce settings page views.
+ */
+ public function track_settings_page_view() {
+ global $current_tab, $current_section;
+
+ $properties = array(
+ 'tab' => $current_tab,
+ 'section' => empty( $current_section ) ? null : $current_section,
+ );
+
+ WC_Tracks::record_event( 'settings_view', $properties );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-status-tracking.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-status-tracking.php
new file mode 100644
index 0000000..ce34a05
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/tracks/events/class-wc-status-tracking.php
@@ -0,0 +1,48 @@
+ $tab,
+ 'tool_used' => isset( $_GET['action'] ) ? sanitize_text_field( wp_unslash( $_GET['action'] ) ) : null,
+ )
+ );
+
+ if ( 'status' === $tab ) {
+ wc_enqueue_js(
+ "
+ $( 'a.debug-report' ).click( function() {
+ window.wcTracks.recordEvent( 'status_view_reports' );
+ } );
+ "
+ );
+ }
+ }
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/traits/trait-wc-item-totals.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/traits/trait-wc-item-totals.php
new file mode 100644
index 0000000..4bc8c9c
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/traits/trait-wc-item-totals.php
@@ -0,0 +1,91 @@
+ 'parent',
+ 'id' => 'term_id',
+ 'slug' => 'slug',
+ );
+
+ /**
+ * Starts the list before the elements are added.
+ *
+ * @see Walker::start_el()
+ * @since 2.1.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param object $cat Category.
+ * @param int $depth Depth of category in reference to parents.
+ * @param array $args Arguments.
+ * @param int $current_object_id Current object ID.
+ */
+ public function start_el( &$output, $cat, $depth = 0, $args = array(), $current_object_id = 0 ) {
+
+ if ( ! empty( $args['hierarchical'] ) ) {
+ $pad = str_repeat( ' ', $depth * 3 );
+ } else {
+ $pad = '';
+ }
+
+ $cat_name = apply_filters( 'list_product_cats', $cat->name, $cat );
+ $value = ( isset( $args['value'] ) && 'id' === $args['value'] ) ? $cat->term_id : $cat->slug;
+ $output .= "\t\n";
+ }
+
+ /**
+ * Traverse elements to create list from elements.
+ *
+ * Display one element if the element doesn't have any children otherwise,
+ * display the element and its children. Will only traverse up to the max.
+ * depth and no ignore elements under that depth. It is possible to set the.
+ * max depth to include all depths, see walk() method.
+ *
+ * This method shouldn't be called directly, use the walk() method instead.
+ *
+ * @since 2.5.0
+ *
+ * @param object $element Data object.
+ * @param array $children_elements List of elements to continue traversing.
+ * @param int $max_depth Max depth to traverse.
+ * @param int $depth Depth of current element.
+ * @param array $args Arguments.
+ * @param string $output Passed by reference. Used to append additional content.
+ * @return null Null on failure with no changes to parameters.
+ */
+ public function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) {
+ if ( ! $element || ( 0 === $element->count && ! empty( $args[0]['hide_empty'] ) ) ) {
+ return;
+ }
+ parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
+ }
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/walkers/class-wc-product-cat-list-walker.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/walkers/class-wc-product-cat-list-walker.php
new file mode 100644
index 0000000..3580184
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/walkers/class-wc-product-cat-list-walker.php
@@ -0,0 +1,153 @@
+ 'parent',
+ 'id' => 'term_id',
+ 'slug' => 'slug',
+ );
+
+ /**
+ * Starts the list before the elements are added.
+ *
+ * @see Walker::start_lvl()
+ * @since 2.1.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param int $depth Depth of category. Used for tab indentation.
+ * @param array $args Will only append content if style argument value is 'list'.
+ */
+ public function start_lvl( &$output, $depth = 0, $args = array() ) {
+ if ( 'list' !== $args['style'] ) {
+ return;
+ }
+
+ $indent = str_repeat( "\t", $depth );
+ $output .= "$indent
\n";
+ }
+
+ /**
+ * Ends the list of after the elements are added.
+ *
+ * @see Walker::end_lvl()
+ * @since 2.1.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param int $depth Depth of category. Used for tab indentation.
+ * @param array $args Will only append content if style argument value is 'list'.
+ */
+ public function end_lvl( &$output, $depth = 0, $args = array() ) {
+ if ( 'list' !== $args['style'] ) {
+ return;
+ }
+
+ $indent = str_repeat( "\t", $depth );
+ $output .= "$indent
\n";
+ }
+
+ /**
+ * Start the element output.
+ *
+ * @see Walker::start_el()
+ * @since 2.1.0
+ *
+ * @param string $output Passed by reference. Used to append additional content.
+ * @param object $cat Category.
+ * @param int $depth Depth of category in reference to parents.
+ * @param array $args Arguments.
+ * @param integer $current_object_id Current object ID.
+ */
+ public function start_el( &$output, $cat, $depth = 0, $args = array(), $current_object_id = 0 ) {
+ $cat_id = intval( $cat->term_id );
+
+ $output .= '' . $filter_template . '
' ), '2.1' );
+ return;
+ }
+ $template = $filter_template;
+ }
+
+ $action_args = array(
+ 'template_name' => $template_name,
+ 'template_path' => $template_path,
+ 'located' => $template,
+ 'args' => $args,
+ );
+
+ if ( ! empty( $args ) && is_array( $args ) ) {
+ if ( isset( $args['action_args'] ) ) {
+ wc_doing_it_wrong(
+ __FUNCTION__,
+ __( 'action_args should not be overwritten when calling wc_get_template.', 'woocommerce' ),
+ '3.6.0'
+ );
+ unset( $args['action_args'] );
+ }
+ extract( $args ); // @codingStandardsIgnoreLine
+ }
+
+ do_action( 'woocommerce_before_template_part', $action_args['template_name'], $action_args['template_path'], $action_args['located'], $action_args['args'] );
+
+ include $action_args['located'];
+
+ do_action( 'woocommerce_after_template_part', $action_args['template_name'], $action_args['template_path'], $action_args['located'], $action_args['args'] );
+}
+
+/**
+ * Like wc_get_template, but returns the HTML instead of outputting.
+ *
+ * @see wc_get_template
+ * @since 2.5.0
+ * @param string $template_name Template name.
+ * @param array $args Arguments. (default: array).
+ * @param string $template_path Template path. (default: '').
+ * @param string $default_path Default path. (default: '').
+ *
+ * @return string
+ */
+function wc_get_template_html( $template_name, $args = array(), $template_path = '', $default_path = '' ) {
+ ob_start();
+ wc_get_template( $template_name, $args, $template_path, $default_path );
+ return ob_get_clean();
+}
+/**
+ * Locate a template and return the path for inclusion.
+ *
+ * This is the load order:
+ *
+ * yourtheme/$template_path/$template_name
+ * yourtheme/$template_name
+ * $default_path/$template_name
+ *
+ * @param string $template_name Template name.
+ * @param string $template_path Template path. (default: '').
+ * @param string $default_path Default path. (default: '').
+ * @return string
+ */
+function wc_locate_template( $template_name, $template_path = '', $default_path = '' ) {
+ if ( ! $template_path ) {
+ $template_path = WC()->template_path();
+ }
+
+ if ( ! $default_path ) {
+ $default_path = WC()->plugin_path() . '/templates/';
+ }
+
+ // Look within passed path within the theme - this is priority.
+ if ( false !== strpos( $template_name, 'product_cat' ) || false !== strpos( $template_name, 'product_tag' ) ) {
+ $cs_template = str_replace( '_', '-', $template_name );
+ $template = locate_template(
+ array(
+ trailingslashit( $template_path ) . $cs_template,
+ $cs_template,
+ )
+ );
+ }
+
+ if ( empty( $template ) ) {
+ $template = locate_template(
+ array(
+ trailingslashit( $template_path ) . $template_name,
+ $template_name,
+ )
+ );
+ }
+
+ // Get default template/.
+ if ( ! $template || WC_TEMPLATE_DEBUG_MODE ) {
+ if ( empty( $cs_template ) ) {
+ $template = $default_path . $template_name;
+ } else {
+ $template = $default_path . $cs_template;
+ }
+ }
+
+ // Return what we found.
+ return apply_filters( 'woocommerce_locate_template', $template, $template_name, $template_path );
+}
+
+/**
+ * Add a template to the template cache.
+ *
+ * @since 4.3.0
+ * @param string $cache_key Object cache key.
+ * @param string $template Located template.
+ */
+function wc_set_template_cache( $cache_key, $template ) {
+ wp_cache_set( $cache_key, $template, 'woocommerce' );
+
+ $cached_templates = wp_cache_get( 'cached_templates', 'woocommerce' );
+ if ( is_array( $cached_templates ) ) {
+ $cached_templates[] = $cache_key;
+ } else {
+ $cached_templates = array( $cache_key );
+ }
+
+ wp_cache_set( 'cached_templates', $cached_templates, 'woocommerce' );
+}
+
+/**
+ * Clear the template cache.
+ *
+ * @since 4.3.0
+ */
+function wc_clear_template_cache() {
+ $cached_templates = wp_cache_get( 'cached_templates', 'woocommerce' );
+ if ( is_array( $cached_templates ) ) {
+ foreach ( $cached_templates as $cache_key ) {
+ wp_cache_delete( $cache_key, 'woocommerce' );
+ }
+
+ wp_cache_delete( 'cached_templates', 'woocommerce' );
+ }
+}
+
+/**
+ * Get Base Currency Code.
+ *
+ * @return string
+ */
+function get_woocommerce_currency() {
+ return apply_filters( 'woocommerce_currency', get_option( 'woocommerce_currency' ) );
+}
+
+/**
+ * Get full list of currency codes.
+ *
+ * Currency symbols and names should follow the Unicode CLDR recommendation (http://cldr.unicode.org/translation/currency-names)
+ *
+ * @return array
+ */
+function get_woocommerce_currencies() {
+ static $currencies;
+
+ if ( ! isset( $currencies ) ) {
+ $currencies = array_unique(
+ apply_filters(
+ 'woocommerce_currencies',
+ array(
+ 'AED' => __( 'United Arab Emirates dirham', 'woocommerce' ),
+ 'AFN' => __( 'Afghan afghani', 'woocommerce' ),
+ 'ALL' => __( 'Albanian lek', 'woocommerce' ),
+ 'AMD' => __( 'Armenian dram', 'woocommerce' ),
+ 'ANG' => __( 'Netherlands Antillean guilder', 'woocommerce' ),
+ 'AOA' => __( 'Angolan kwanza', 'woocommerce' ),
+ 'ARS' => __( 'Argentine peso', 'woocommerce' ),
+ 'AUD' => __( 'Australian dollar', 'woocommerce' ),
+ 'AWG' => __( 'Aruban florin', 'woocommerce' ),
+ 'AZN' => __( 'Azerbaijani manat', 'woocommerce' ),
+ 'BAM' => __( 'Bosnia and Herzegovina convertible mark', 'woocommerce' ),
+ 'BBD' => __( 'Barbadian dollar', 'woocommerce' ),
+ 'BDT' => __( 'Bangladeshi taka', 'woocommerce' ),
+ 'BGN' => __( 'Bulgarian lev', 'woocommerce' ),
+ 'BHD' => __( 'Bahraini dinar', 'woocommerce' ),
+ 'BIF' => __( 'Burundian franc', 'woocommerce' ),
+ 'BMD' => __( 'Bermudian dollar', 'woocommerce' ),
+ 'BND' => __( 'Brunei dollar', 'woocommerce' ),
+ 'BOB' => __( 'Bolivian boliviano', 'woocommerce' ),
+ 'BRL' => __( 'Brazilian real', 'woocommerce' ),
+ 'BSD' => __( 'Bahamian dollar', 'woocommerce' ),
+ 'BTC' => __( 'Bitcoin', 'woocommerce' ),
+ 'BTN' => __( 'Bhutanese ngultrum', 'woocommerce' ),
+ 'BWP' => __( 'Botswana pula', 'woocommerce' ),
+ 'BYR' => __( 'Belarusian ruble (old)', 'woocommerce' ),
+ 'BYN' => __( 'Belarusian ruble', 'woocommerce' ),
+ 'BZD' => __( 'Belize dollar', 'woocommerce' ),
+ 'CAD' => __( 'Canadian dollar', 'woocommerce' ),
+ 'CDF' => __( 'Congolese franc', 'woocommerce' ),
+ 'CHF' => __( 'Swiss franc', 'woocommerce' ),
+ 'CLP' => __( 'Chilean peso', 'woocommerce' ),
+ 'CNY' => __( 'Chinese yuan', 'woocommerce' ),
+ 'COP' => __( 'Colombian peso', 'woocommerce' ),
+ 'CRC' => __( 'Costa Rican colón', 'woocommerce' ),
+ 'CUC' => __( 'Cuban convertible peso', 'woocommerce' ),
+ 'CUP' => __( 'Cuban peso', 'woocommerce' ),
+ 'CVE' => __( 'Cape Verdean escudo', 'woocommerce' ),
+ 'CZK' => __( 'Czech koruna', 'woocommerce' ),
+ 'DJF' => __( 'Djiboutian franc', 'woocommerce' ),
+ 'DKK' => __( 'Danish krone', 'woocommerce' ),
+ 'DOP' => __( 'Dominican peso', 'woocommerce' ),
+ 'DZD' => __( 'Algerian dinar', 'woocommerce' ),
+ 'EGP' => __( 'Egyptian pound', 'woocommerce' ),
+ 'ERN' => __( 'Eritrean nakfa', 'woocommerce' ),
+ 'ETB' => __( 'Ethiopian birr', 'woocommerce' ),
+ 'EUR' => __( 'Euro', 'woocommerce' ),
+ 'FJD' => __( 'Fijian dollar', 'woocommerce' ),
+ 'FKP' => __( 'Falkland Islands pound', 'woocommerce' ),
+ 'GBP' => __( 'Pound sterling', 'woocommerce' ),
+ 'GEL' => __( 'Georgian lari', 'woocommerce' ),
+ 'GGP' => __( 'Guernsey pound', 'woocommerce' ),
+ 'GHS' => __( 'Ghana cedi', 'woocommerce' ),
+ 'GIP' => __( 'Gibraltar pound', 'woocommerce' ),
+ 'GMD' => __( 'Gambian dalasi', 'woocommerce' ),
+ 'GNF' => __( 'Guinean franc', 'woocommerce' ),
+ 'GTQ' => __( 'Guatemalan quetzal', 'woocommerce' ),
+ 'GYD' => __( 'Guyanese dollar', 'woocommerce' ),
+ 'HKD' => __( 'Hong Kong dollar', 'woocommerce' ),
+ 'HNL' => __( 'Honduran lempira', 'woocommerce' ),
+ 'HRK' => __( 'Croatian kuna', 'woocommerce' ),
+ 'HTG' => __( 'Haitian gourde', 'woocommerce' ),
+ 'HUF' => __( 'Hungarian forint', 'woocommerce' ),
+ 'IDR' => __( 'Indonesian rupiah', 'woocommerce' ),
+ 'ILS' => __( 'Israeli new shekel', 'woocommerce' ),
+ 'IMP' => __( 'Manx pound', 'woocommerce' ),
+ 'INR' => __( 'Indian rupee', 'woocommerce' ),
+ 'IQD' => __( 'Iraqi dinar', 'woocommerce' ),
+ 'IRR' => __( 'Iranian rial', 'woocommerce' ),
+ 'IRT' => __( 'Iranian toman', 'woocommerce' ),
+ 'ISK' => __( 'Icelandic króna', 'woocommerce' ),
+ 'JEP' => __( 'Jersey pound', 'woocommerce' ),
+ 'JMD' => __( 'Jamaican dollar', 'woocommerce' ),
+ 'JOD' => __( 'Jordanian dinar', 'woocommerce' ),
+ 'JPY' => __( 'Japanese yen', 'woocommerce' ),
+ 'KES' => __( 'Kenyan shilling', 'woocommerce' ),
+ 'KGS' => __( 'Kyrgyzstani som', 'woocommerce' ),
+ 'KHR' => __( 'Cambodian riel', 'woocommerce' ),
+ 'KMF' => __( 'Comorian franc', 'woocommerce' ),
+ 'KPW' => __( 'North Korean won', 'woocommerce' ),
+ 'KRW' => __( 'South Korean won', 'woocommerce' ),
+ 'KWD' => __( 'Kuwaiti dinar', 'woocommerce' ),
+ 'KYD' => __( 'Cayman Islands dollar', 'woocommerce' ),
+ 'KZT' => __( 'Kazakhstani tenge', 'woocommerce' ),
+ 'LAK' => __( 'Lao kip', 'woocommerce' ),
+ 'LBP' => __( 'Lebanese pound', 'woocommerce' ),
+ 'LKR' => __( 'Sri Lankan rupee', 'woocommerce' ),
+ 'LRD' => __( 'Liberian dollar', 'woocommerce' ),
+ 'LSL' => __( 'Lesotho loti', 'woocommerce' ),
+ 'LYD' => __( 'Libyan dinar', 'woocommerce' ),
+ 'MAD' => __( 'Moroccan dirham', 'woocommerce' ),
+ 'MDL' => __( 'Moldovan leu', 'woocommerce' ),
+ 'MGA' => __( 'Malagasy ariary', 'woocommerce' ),
+ 'MKD' => __( 'Macedonian denar', 'woocommerce' ),
+ 'MMK' => __( 'Burmese kyat', 'woocommerce' ),
+ 'MNT' => __( 'Mongolian tögrög', 'woocommerce' ),
+ 'MOP' => __( 'Macanese pataca', 'woocommerce' ),
+ 'MRU' => __( 'Mauritanian ouguiya', 'woocommerce' ),
+ 'MUR' => __( 'Mauritian rupee', 'woocommerce' ),
+ 'MVR' => __( 'Maldivian rufiyaa', 'woocommerce' ),
+ 'MWK' => __( 'Malawian kwacha', 'woocommerce' ),
+ 'MXN' => __( 'Mexican peso', 'woocommerce' ),
+ 'MYR' => __( 'Malaysian ringgit', 'woocommerce' ),
+ 'MZN' => __( 'Mozambican metical', 'woocommerce' ),
+ 'NAD' => __( 'Namibian dollar', 'woocommerce' ),
+ 'NGN' => __( 'Nigerian naira', 'woocommerce' ),
+ 'NIO' => __( 'Nicaraguan córdoba', 'woocommerce' ),
+ 'NOK' => __( 'Norwegian krone', 'woocommerce' ),
+ 'NPR' => __( 'Nepalese rupee', 'woocommerce' ),
+ 'NZD' => __( 'New Zealand dollar', 'woocommerce' ),
+ 'OMR' => __( 'Omani rial', 'woocommerce' ),
+ 'PAB' => __( 'Panamanian balboa', 'woocommerce' ),
+ 'PEN' => __( 'Sol', 'woocommerce' ),
+ 'PGK' => __( 'Papua New Guinean kina', 'woocommerce' ),
+ 'PHP' => __( 'Philippine peso', 'woocommerce' ),
+ 'PKR' => __( 'Pakistani rupee', 'woocommerce' ),
+ 'PLN' => __( 'Polish złoty', 'woocommerce' ),
+ 'PRB' => __( 'Transnistrian ruble', 'woocommerce' ),
+ 'PYG' => __( 'Paraguayan guaraní', 'woocommerce' ),
+ 'QAR' => __( 'Qatari riyal', 'woocommerce' ),
+ 'RON' => __( 'Romanian leu', 'woocommerce' ),
+ 'RSD' => __( 'Serbian dinar', 'woocommerce' ),
+ 'RUB' => __( 'Russian ruble', 'woocommerce' ),
+ 'RWF' => __( 'Rwandan franc', 'woocommerce' ),
+ 'SAR' => __( 'Saudi riyal', 'woocommerce' ),
+ 'SBD' => __( 'Solomon Islands dollar', 'woocommerce' ),
+ 'SCR' => __( 'Seychellois rupee', 'woocommerce' ),
+ 'SDG' => __( 'Sudanese pound', 'woocommerce' ),
+ 'SEK' => __( 'Swedish krona', 'woocommerce' ),
+ 'SGD' => __( 'Singapore dollar', 'woocommerce' ),
+ 'SHP' => __( 'Saint Helena pound', 'woocommerce' ),
+ 'SLL' => __( 'Sierra Leonean leone', 'woocommerce' ),
+ 'SOS' => __( 'Somali shilling', 'woocommerce' ),
+ 'SRD' => __( 'Surinamese dollar', 'woocommerce' ),
+ 'SSP' => __( 'South Sudanese pound', 'woocommerce' ),
+ 'STN' => __( 'São Tomé and Príncipe dobra', 'woocommerce' ),
+ 'SYP' => __( 'Syrian pound', 'woocommerce' ),
+ 'SZL' => __( 'Swazi lilangeni', 'woocommerce' ),
+ 'THB' => __( 'Thai baht', 'woocommerce' ),
+ 'TJS' => __( 'Tajikistani somoni', 'woocommerce' ),
+ 'TMT' => __( 'Turkmenistan manat', 'woocommerce' ),
+ 'TND' => __( 'Tunisian dinar', 'woocommerce' ),
+ 'TOP' => __( 'Tongan paʻanga', 'woocommerce' ),
+ 'TRY' => __( 'Turkish lira', 'woocommerce' ),
+ 'TTD' => __( 'Trinidad and Tobago dollar', 'woocommerce' ),
+ 'TWD' => __( 'New Taiwan dollar', 'woocommerce' ),
+ 'TZS' => __( 'Tanzanian shilling', 'woocommerce' ),
+ 'UAH' => __( 'Ukrainian hryvnia', 'woocommerce' ),
+ 'UGX' => __( 'Ugandan shilling', 'woocommerce' ),
+ 'USD' => __( 'United States (US) dollar', 'woocommerce' ),
+ 'UYU' => __( 'Uruguayan peso', 'woocommerce' ),
+ 'UZS' => __( 'Uzbekistani som', 'woocommerce' ),
+ 'VEF' => __( 'Venezuelan bolívar', 'woocommerce' ),
+ 'VES' => __( 'Bolívar soberano', 'woocommerce' ),
+ 'VND' => __( 'Vietnamese đồng', 'woocommerce' ),
+ 'VUV' => __( 'Vanuatu vatu', 'woocommerce' ),
+ 'WST' => __( 'Samoan tālā', 'woocommerce' ),
+ 'XAF' => __( 'Central African CFA franc', 'woocommerce' ),
+ 'XCD' => __( 'East Caribbean dollar', 'woocommerce' ),
+ 'XOF' => __( 'West African CFA franc', 'woocommerce' ),
+ 'XPF' => __( 'CFP franc', 'woocommerce' ),
+ 'YER' => __( 'Yemeni rial', 'woocommerce' ),
+ 'ZAR' => __( 'South African rand', 'woocommerce' ),
+ 'ZMW' => __( 'Zambian kwacha', 'woocommerce' ),
+ )
+ )
+ );
+ }
+
+ return $currencies;
+}
+
+/**
+ * Get all available Currency symbols.
+ *
+ * Currency symbols and names should follow the Unicode CLDR recommendation (http://cldr.unicode.org/translation/currency-names)
+ *
+ * @since 4.1.0
+ * @return array
+ */
+function get_woocommerce_currency_symbols() {
+
+ $symbols = apply_filters(
+ 'woocommerce_currency_symbols',
+ array(
+ 'AED' => 'د.إ',
+ 'AFN' => '؋',
+ 'ALL' => 'L',
+ 'AMD' => 'AMD',
+ 'ANG' => 'ƒ',
+ 'AOA' => 'Kz',
+ 'ARS' => '$',
+ 'AUD' => '$',
+ 'AWG' => 'Afl.',
+ 'AZN' => 'AZN',
+ 'BAM' => 'KM',
+ 'BBD' => '$',
+ 'BDT' => '৳ ',
+ 'BGN' => 'лв.',
+ 'BHD' => '.د.ب',
+ 'BIF' => 'Fr',
+ 'BMD' => '$',
+ 'BND' => '$',
+ 'BOB' => 'Bs.',
+ 'BRL' => 'R$',
+ 'BSD' => '$',
+ 'BTC' => '฿',
+ 'BTN' => 'Nu.',
+ 'BWP' => 'P',
+ 'BYR' => 'Br',
+ 'BYN' => 'Br',
+ 'BZD' => '$',
+ 'CAD' => '$',
+ 'CDF' => 'Fr',
+ 'CHF' => 'CHF',
+ 'CLP' => '$',
+ 'CNY' => '¥',
+ 'COP' => '$',
+ 'CRC' => '₡',
+ 'CUC' => '$',
+ 'CUP' => '$',
+ 'CVE' => '$',
+ 'CZK' => 'Kč',
+ 'DJF' => 'Fr',
+ 'DKK' => 'DKK',
+ 'DOP' => 'RD$',
+ 'DZD' => 'د.ج',
+ 'EGP' => 'EGP',
+ 'ERN' => 'Nfk',
+ 'ETB' => 'Br',
+ 'EUR' => '€',
+ 'FJD' => '$',
+ 'FKP' => '£',
+ 'GBP' => '£',
+ 'GEL' => '₾',
+ 'GGP' => '£',
+ 'GHS' => '₵',
+ 'GIP' => '£',
+ 'GMD' => 'D',
+ 'GNF' => 'Fr',
+ 'GTQ' => 'Q',
+ 'GYD' => '$',
+ 'HKD' => '$',
+ 'HNL' => 'L',
+ 'HRK' => 'kn',
+ 'HTG' => 'G',
+ 'HUF' => 'Ft',
+ 'IDR' => 'Rp',
+ 'ILS' => '₪',
+ 'IMP' => '£',
+ 'INR' => '₹',
+ 'IQD' => 'ع.د',
+ 'IRR' => '﷼',
+ 'IRT' => 'تومان',
+ 'ISK' => 'kr.',
+ 'JEP' => '£',
+ 'JMD' => '$',
+ 'JOD' => 'د.ا',
+ 'JPY' => '¥',
+ 'KES' => 'KSh',
+ 'KGS' => 'сом',
+ 'KHR' => '៛',
+ 'KMF' => 'Fr',
+ 'KPW' => '₩',
+ 'KRW' => '₩',
+ 'KWD' => 'د.ك',
+ 'KYD' => '$',
+ 'KZT' => '₸',
+ 'LAK' => '₭',
+ 'LBP' => 'ل.ل',
+ 'LKR' => 'රු',
+ 'LRD' => '$',
+ 'LSL' => 'L',
+ 'LYD' => 'ل.د',
+ 'MAD' => 'د.م.',
+ 'MDL' => 'MDL',
+ 'MGA' => 'Ar',
+ 'MKD' => 'ден',
+ 'MMK' => 'Ks',
+ 'MNT' => '₮',
+ 'MOP' => 'P',
+ 'MRU' => 'UM',
+ 'MUR' => '₨',
+ 'MVR' => '.ރ',
+ 'MWK' => 'MK',
+ 'MXN' => '$',
+ 'MYR' => 'RM',
+ 'MZN' => 'MT',
+ 'NAD' => 'N$',
+ 'NGN' => '₦',
+ 'NIO' => 'C$',
+ 'NOK' => 'kr',
+ 'NPR' => '₨',
+ 'NZD' => '$',
+ 'OMR' => 'ر.ع.',
+ 'PAB' => 'B/.',
+ 'PEN' => 'S/',
+ 'PGK' => 'K',
+ 'PHP' => '₱',
+ 'PKR' => '₨',
+ 'PLN' => 'zł',
+ 'PRB' => 'р.',
+ 'PYG' => '₲',
+ 'QAR' => 'ر.ق',
+ 'RMB' => '¥',
+ 'RON' => 'lei',
+ 'RSD' => 'рсд',
+ 'RUB' => '₽',
+ 'RWF' => 'Fr',
+ 'SAR' => 'ر.س',
+ 'SBD' => '$',
+ 'SCR' => '₨',
+ 'SDG' => 'ج.س.',
+ 'SEK' => 'kr',
+ 'SGD' => '$',
+ 'SHP' => '£',
+ 'SLL' => 'Le',
+ 'SOS' => 'Sh',
+ 'SRD' => '$',
+ 'SSP' => '£',
+ 'STN' => 'Db',
+ 'SYP' => 'ل.س',
+ 'SZL' => 'L',
+ 'THB' => '฿',
+ 'TJS' => 'ЅМ',
+ 'TMT' => 'm',
+ 'TND' => 'د.ت',
+ 'TOP' => 'T$',
+ 'TRY' => '₺',
+ 'TTD' => '$',
+ 'TWD' => 'NT$',
+ 'TZS' => 'Sh',
+ 'UAH' => '₴',
+ 'UGX' => 'UGX',
+ 'USD' => '$',
+ 'UYU' => '$',
+ 'UZS' => 'UZS',
+ 'VEF' => 'Bs F',
+ 'VES' => 'Bs.S',
+ 'VND' => '₫',
+ 'VUV' => 'Vt',
+ 'WST' => 'T',
+ 'XAF' => 'CFA',
+ 'XCD' => '$',
+ 'XOF' => 'CFA',
+ 'XPF' => 'Fr',
+ 'YER' => '﷼',
+ 'ZAR' => 'R',
+ 'ZMW' => 'ZK',
+ )
+ );
+
+ return $symbols;
+}
+
+/**
+ * Get Currency symbol.
+ *
+ * Currency symbols and names should follow the Unicode CLDR recommendation (http://cldr.unicode.org/translation/currency-names)
+ *
+ * @param string $currency Currency. (default: '').
+ * @return string
+ */
+function get_woocommerce_currency_symbol( $currency = '' ) {
+ if ( ! $currency ) {
+ $currency = get_woocommerce_currency();
+ }
+
+ $symbols = get_woocommerce_currency_symbols();
+
+ $currency_symbol = isset( $symbols[ $currency ] ) ? $symbols[ $currency ] : '';
+
+ return apply_filters( 'woocommerce_currency_symbol', $currency_symbol, $currency );
+}
+
+/**
+ * Send HTML emails from WooCommerce.
+ *
+ * @param mixed $to Receiver.
+ * @param mixed $subject Subject.
+ * @param mixed $message Message.
+ * @param string $headers Headers. (default: "Content-Type: text/html\r\n").
+ * @param string $attachments Attachments. (default: "").
+ * @return bool
+ */
+function wc_mail( $to, $subject, $message, $headers = "Content-Type: text/html\r\n", $attachments = '' ) {
+ $mailer = WC()->mailer();
+
+ return $mailer->send( $to, $subject, $message, $headers, $attachments );
+}
+
+/**
+ * Return "theme support" values from the current theme, if set.
+ *
+ * @since 3.3.0
+ * @param string $prop Name of prop (or key::subkey for arrays of props) if you want a specific value. Leave blank to get all props as an array.
+ * @param mixed $default Optional value to return if the theme does not declare support for a prop.
+ * @return mixed Value of prop(s).
+ */
+function wc_get_theme_support( $prop = '', $default = null ) {
+ $theme_support = get_theme_support( 'woocommerce' );
+ $theme_support = is_array( $theme_support ) ? $theme_support[0] : false;
+
+ if ( ! $theme_support ) {
+ return $default;
+ }
+
+ if ( $prop ) {
+ $prop_stack = explode( '::', $prop );
+ $prop_key = array_shift( $prop_stack );
+
+ if ( isset( $theme_support[ $prop_key ] ) ) {
+ $value = $theme_support[ $prop_key ];
+
+ if ( count( $prop_stack ) ) {
+ foreach ( $prop_stack as $prop_key ) {
+ if ( is_array( $value ) && isset( $value[ $prop_key ] ) ) {
+ $value = $value[ $prop_key ];
+ } else {
+ $value = $default;
+ break;
+ }
+ }
+ }
+ } else {
+ $value = $default;
+ }
+
+ return $value;
+ }
+
+ return $theme_support;
+}
+
+/**
+ * Get an image size by name or defined dimensions.
+ *
+ * The returned variable is filtered by woocommerce_get_image_size_{image_size} filter to
+ * allow 3rd party customisation.
+ *
+ * Sizes defined by the theme take priority over settings. Settings are hidden when a theme
+ * defines sizes.
+ *
+ * @param array|string $image_size Name of the image size to get, or an array of dimensions.
+ * @return array Array of dimensions including width, height, and cropping mode. Cropping mode is 0 for no crop, and 1 for hard crop.
+ */
+function wc_get_image_size( $image_size ) {
+ $cache_key = 'size-' . ( is_array( $image_size ) ? implode( '-', $image_size ) : $image_size );
+ $size = wp_cache_get( $cache_key, 'woocommerce' );
+
+ if ( $size ) {
+ return $size;
+ }
+
+ $size = array(
+ 'width' => 600,
+ 'height' => 600,
+ 'crop' => 1,
+ );
+
+ if ( is_array( $image_size ) ) {
+ $size = array(
+ 'width' => isset( $image_size[0] ) ? absint( $image_size[0] ) : 600,
+ 'height' => isset( $image_size[1] ) ? absint( $image_size[1] ) : 600,
+ 'crop' => isset( $image_size[2] ) ? absint( $image_size[2] ) : 1,
+ );
+ $image_size = $size['width'] . '_' . $size['height'];
+ } else {
+ $image_size = str_replace( 'woocommerce_', '', $image_size );
+
+ // Legacy size mapping.
+ if ( 'shop_single' === $image_size ) {
+ $image_size = 'single';
+ } elseif ( 'shop_catalog' === $image_size ) {
+ $image_size = 'thumbnail';
+ } elseif ( 'shop_thumbnail' === $image_size ) {
+ $image_size = 'gallery_thumbnail';
+ }
+
+ if ( 'single' === $image_size ) {
+ $size['width'] = absint( wc_get_theme_support( 'single_image_width', get_option( 'woocommerce_single_image_width', 600 ) ) );
+ $size['height'] = '';
+ $size['crop'] = 0;
+
+ } elseif ( 'gallery_thumbnail' === $image_size ) {
+ $size['width'] = absint( wc_get_theme_support( 'gallery_thumbnail_image_width', 100 ) );
+ $size['height'] = $size['width'];
+ $size['crop'] = 1;
+
+ } elseif ( 'thumbnail' === $image_size ) {
+ $size['width'] = absint( wc_get_theme_support( 'thumbnail_image_width', get_option( 'woocommerce_thumbnail_image_width', 300 ) ) );
+ $cropping = get_option( 'woocommerce_thumbnail_cropping', '1:1' );
+
+ if ( 'uncropped' === $cropping ) {
+ $size['height'] = '';
+ $size['crop'] = 0;
+ } elseif ( 'custom' === $cropping ) {
+ $width = max( 1, get_option( 'woocommerce_thumbnail_cropping_custom_width', '4' ) );
+ $height = max( 1, get_option( 'woocommerce_thumbnail_cropping_custom_height', '3' ) );
+ $size['height'] = absint( NumberUtil::round( ( $size['width'] / $width ) * $height ) );
+ $size['crop'] = 1;
+ } else {
+ $cropping_split = explode( ':', $cropping );
+ $width = max( 1, current( $cropping_split ) );
+ $height = max( 1, end( $cropping_split ) );
+ $size['height'] = absint( NumberUtil::round( ( $size['width'] / $width ) * $height ) );
+ $size['crop'] = 1;
+ }
+ }
+ }
+
+ $size = apply_filters( 'woocommerce_get_image_size_' . $image_size, $size );
+
+ wp_cache_set( $cache_key, $size, 'woocommerce' );
+
+ return $size;
+}
+
+/**
+ * Queue some JavaScript code to be output in the footer.
+ *
+ * @param string $code Code.
+ */
+function wc_enqueue_js( $code ) {
+ global $wc_queued_js;
+
+ if ( empty( $wc_queued_js ) ) {
+ $wc_queued_js = '';
+ }
+
+ $wc_queued_js .= "\n" . $code . "\n";
+}
+
+/**
+ * Output any queued javascript code in the footer.
+ */
+function wc_print_js() {
+ global $wc_queued_js;
+
+ if ( ! empty( $wc_queued_js ) ) {
+ // Sanitize.
+ $wc_queued_js = wp_check_invalid_utf8( $wc_queued_js );
+ $wc_queued_js = preg_replace( '/(x)?0*(?(1)27|39);?/i', "'", $wc_queued_js );
+ $wc_queued_js = str_replace( "\r", '', $wc_queued_js );
+
+ $js = "\n\n";
+
+ /**
+ * Queued jsfilter.
+ *
+ * @since 2.6.0
+ * @param string $js JavaScript code.
+ */
+ echo apply_filters( 'woocommerce_queued_js', $js ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+
+ unset( $wc_queued_js );
+ }
+}
+
+/**
+ * Set a cookie - wrapper for setcookie using WP constants.
+ *
+ * @param string $name Name of the cookie being set.
+ * @param string $value Value of the cookie.
+ * @param integer $expire Expiry of the cookie.
+ * @param bool $secure Whether the cookie should be served only over https.
+ * @param bool $httponly Whether the cookie is only accessible over HTTP, not scripting languages like JavaScript. @since 3.6.0.
+ */
+function wc_setcookie( $name, $value, $expire = 0, $secure = false, $httponly = false ) {
+ if ( ! headers_sent() ) {
+ setcookie( $name, $value, $expire, COOKIEPATH ? COOKIEPATH : '/', COOKIE_DOMAIN, $secure, apply_filters( 'woocommerce_cookie_httponly', $httponly, $name, $value, $expire, $secure ) );
+ } elseif ( Constants::is_true( 'WP_DEBUG' ) ) {
+ headers_sent( $file, $line );
+ trigger_error( "{$name} cookie cannot be set - headers already sent by {$file} on line {$line}", E_USER_NOTICE ); // @codingStandardsIgnoreLine
+ }
+}
+
+/**
+ * Get the URL to the WooCommerce REST API.
+ *
+ * @since 2.1
+ * @param string $path an endpoint to include in the URL.
+ * @return string the URL.
+ */
+function get_woocommerce_api_url( $path ) {
+ if ( Constants::is_defined( 'WC_API_REQUEST_VERSION' ) ) {
+ $version = Constants::get_constant( 'WC_API_REQUEST_VERSION' );
+ } else {
+ $version = substr( WC_API::VERSION, 0, 1 );
+ }
+
+ $url = get_home_url( null, "wc-api/v{$version}/", is_ssl() ? 'https' : 'http' );
+
+ if ( ! empty( $path ) && is_string( $path ) ) {
+ $url .= ltrim( $path, '/' );
+ }
+
+ return $url;
+}
+
+/**
+ * Get a log file path.
+ *
+ * @since 2.2
+ *
+ * @param string $handle name.
+ * @return string the log file path.
+ */
+function wc_get_log_file_path( $handle ) {
+ return WC_Log_Handler_File::get_log_file_path( $handle );
+}
+
+/**
+ * Get a log file name.
+ *
+ * @since 3.3
+ *
+ * @param string $handle Name.
+ * @return string The log file name.
+ */
+function wc_get_log_file_name( $handle ) {
+ return WC_Log_Handler_File::get_log_file_name( $handle );
+}
+
+/**
+ * Recursively get page children.
+ *
+ * @param int $page_id Page ID.
+ * @return int[]
+ */
+function wc_get_page_children( $page_id ) {
+ $page_ids = get_posts(
+ array(
+ 'post_parent' => $page_id,
+ 'post_type' => 'page',
+ 'numberposts' => -1, // @codingStandardsIgnoreLine
+ 'post_status' => 'any',
+ 'fields' => 'ids',
+ )
+ );
+
+ if ( ! empty( $page_ids ) ) {
+ foreach ( $page_ids as $page_id ) {
+ $page_ids = array_merge( $page_ids, wc_get_page_children( $page_id ) );
+ }
+ }
+
+ return $page_ids;
+}
+
+/**
+ * Flushes rewrite rules when the shop page (or it's children) gets saved.
+ */
+function flush_rewrite_rules_on_shop_page_save() {
+ $screen = get_current_screen();
+ $screen_id = $screen ? $screen->id : '';
+
+ // Check if this is the edit page.
+ if ( 'page' !== $screen_id ) {
+ return;
+ }
+
+ // Check if page is edited.
+ if ( empty( $_GET['post'] ) || empty( $_GET['action'] ) || ( isset( $_GET['action'] ) && 'edit' !== $_GET['action'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ return;
+ }
+
+ $post_id = intval( $_GET['post'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ $shop_page_id = wc_get_page_id( 'shop' );
+
+ if ( $shop_page_id === $post_id || in_array( $post_id, wc_get_page_children( $shop_page_id ), true ) ) {
+ do_action( 'woocommerce_flush_rewrite_rules' );
+ }
+}
+add_action( 'admin_footer', 'flush_rewrite_rules_on_shop_page_save' );
+
+/**
+ * Various rewrite rule fixes.
+ *
+ * @since 2.2
+ * @param array $rules Rules.
+ * @return array
+ */
+function wc_fix_rewrite_rules( $rules ) {
+ global $wp_rewrite;
+
+ $permalinks = wc_get_permalink_structure();
+
+ // Fix the rewrite rules when the product permalink have %product_cat% flag.
+ if ( preg_match( '`/(.+)(/%product_cat%)`', $permalinks['product_rewrite_slug'], $matches ) ) {
+ foreach ( $rules as $rule => $rewrite ) {
+ if ( preg_match( '`^' . preg_quote( $matches[1], '`' ) . '/\(`', $rule ) && preg_match( '/^(index\.php\?product_cat)(?!(.*product))/', $rewrite ) ) {
+ unset( $rules[ $rule ] );
+ }
+ }
+ }
+
+ // If the shop page is used as the base, we need to handle shop page subpages to avoid 404s.
+ if ( ! $permalinks['use_verbose_page_rules'] ) {
+ return $rules;
+ }
+
+ $shop_page_id = wc_get_page_id( 'shop' );
+ if ( $shop_page_id ) {
+ $page_rewrite_rules = array();
+ $subpages = wc_get_page_children( $shop_page_id );
+
+ // Subpage rules.
+ foreach ( $subpages as $subpage ) {
+ $uri = get_page_uri( $subpage );
+ $page_rewrite_rules[ $uri . '/?$' ] = 'index.php?pagename=' . $uri;
+ $wp_generated_rewrite_rules = $wp_rewrite->generate_rewrite_rules( $uri, EP_PAGES, true, true, false, false );
+ foreach ( $wp_generated_rewrite_rules as $key => $value ) {
+ $wp_generated_rewrite_rules[ $key ] = $value . '&pagename=' . $uri;
+ }
+ $page_rewrite_rules = array_merge( $page_rewrite_rules, $wp_generated_rewrite_rules );
+ }
+
+ // Merge with rules.
+ $rules = array_merge( $page_rewrite_rules, $rules );
+ }
+
+ return $rules;
+}
+add_filter( 'rewrite_rules_array', 'wc_fix_rewrite_rules' );
+
+/**
+ * Prevent product attachment links from breaking when using complex rewrite structures.
+ *
+ * @param string $link Link.
+ * @param int $post_id Post ID.
+ * @return string
+ */
+function wc_fix_product_attachment_link( $link, $post_id ) {
+ $parent_type = get_post_type( wp_get_post_parent_id( $post_id ) );
+ if ( 'product' === $parent_type || 'product_variation' === $parent_type ) {
+ $link = home_url( '/?attachment_id=' . $post_id );
+ }
+ return $link;
+}
+add_filter( 'attachment_link', 'wc_fix_product_attachment_link', 10, 2 );
+
+/**
+ * Protect downloads from ms-files.php in multisite.
+ *
+ * @param string $rewrite rewrite rules.
+ * @return string
+ */
+function wc_ms_protect_download_rewite_rules( $rewrite ) {
+ if ( ! is_multisite() || 'redirect' === get_option( 'woocommerce_file_download_method' ) ) {
+ return $rewrite;
+ }
+
+ $rule = "\n# WooCommerce Rules - Protect Files from ms-files.php\n\n";
+ $rule .= "' . esc_html( is_object( $class ) ? get_class( $class ) : $class ) . '
',
+ 'woocommerce_logging_class
',
+ 'WC_Logger_Interface
'
+ ),
+ '3.0'
+ );
+
+ $logger = is_a( $logger, 'WC_Logger' ) ? $logger : new WC_Logger();
+ }
+
+ return $logger;
+}
+
+/**
+ * Trigger logging cleanup using the logging class.
+ *
+ * @since 3.4.0
+ */
+function wc_cleanup_logs() {
+ $logger = wc_get_logger();
+
+ if ( is_callable( array( $logger, 'clear_expired_logs' ) ) ) {
+ $logger->clear_expired_logs();
+ }
+}
+add_action( 'woocommerce_cleanup_logs', 'wc_cleanup_logs' );
+
+/**
+ * Prints human-readable information about a variable.
+ *
+ * Some server environments block some debugging functions. This function provides a safe way to
+ * turn an expression into a printable, readable form without calling blocked functions.
+ *
+ * @since 3.0
+ *
+ * @param mixed $expression The expression to be printed.
+ * @param bool $return Optional. Default false. Set to true to return the human-readable string.
+ * @return string|bool False if expression could not be printed. True if the expression was printed.
+ * If $return is true, a string representation will be returned.
+ */
+function wc_print_r( $expression, $return = false ) {
+ $alternatives = array(
+ array(
+ 'func' => 'print_r',
+ 'args' => array( $expression, true ),
+ ),
+ array(
+ 'func' => 'var_export',
+ 'args' => array( $expression, true ),
+ ),
+ array(
+ 'func' => 'json_encode',
+ 'args' => array( $expression ),
+ ),
+ array(
+ 'func' => 'serialize',
+ 'args' => array( $expression ),
+ ),
+ );
+
+ $alternatives = apply_filters( 'woocommerce_print_r_alternatives', $alternatives, $expression );
+
+ foreach ( $alternatives as $alternative ) {
+ if ( function_exists( $alternative['func'] ) ) {
+ $res = $alternative['func']( ...$alternative['args'] );
+ if ( $return ) {
+ return $res; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ }
+
+ echo $res; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Registers the default log handler.
+ *
+ * @since 3.0
+ * @param array $handlers Handlers.
+ * @return array
+ */
+function wc_register_default_log_handler( $handlers ) {
+ $handler_class = Constants::get_constant( 'WC_LOG_HANDLER' );
+ if ( ! class_exists( $handler_class ) ) {
+ $handler_class = WC_Log_Handler_File::class;
+ }
+
+ array_push( $handlers, new $handler_class() );
+
+ return $handlers;
+}
+add_filter( 'woocommerce_register_log_handlers', 'wc_register_default_log_handler' );
+
+/**
+ * Based on wp_list_pluck, this calls a method instead of returning a property.
+ *
+ * @since 3.0.0
+ * @param array $list List of objects or arrays.
+ * @param int|string $callback_or_field Callback method from the object to place instead of the entire object.
+ * @param int|string $index_key Optional. Field from the object to use as keys for the new array.
+ * Default null.
+ * @return array Array of values.
+ */
+function wc_list_pluck( $list, $callback_or_field, $index_key = null ) {
+ // Use wp_list_pluck if this isn't a callback.
+ $first_el = current( $list );
+ if ( ! is_object( $first_el ) || ! is_callable( array( $first_el, $callback_or_field ) ) ) {
+ return wp_list_pluck( $list, $callback_or_field, $index_key );
+ }
+ if ( ! $index_key ) {
+ /*
+ * This is simple. Could at some point wrap array_column()
+ * if we knew we had an array of arrays.
+ */
+ foreach ( $list as $key => $value ) {
+ $list[ $key ] = $value->{$callback_or_field}();
+ }
+ return $list;
+ }
+
+ /*
+ * When index_key is not set for a particular item, push the value
+ * to the end of the stack. This is how array_column() behaves.
+ */
+ $newlist = array();
+ foreach ( $list as $value ) {
+ // Get index. @since 3.2.0 this supports a callback.
+ if ( is_callable( array( $value, $index_key ) ) ) {
+ $newlist[ $value->{$index_key}() ] = $value->{$callback_or_field}();
+ } elseif ( isset( $value->$index_key ) ) {
+ $newlist[ $value->$index_key ] = $value->{$callback_or_field}();
+ } else {
+ $newlist[] = $value->{$callback_or_field}();
+ }
+ }
+ return $newlist;
+}
+
+/**
+ * Get permalink settings for things like products and taxonomies.
+ *
+ * As of 3.3.0, the permalink settings are stored to the option instead of
+ * being blank and inheritting from the locale. This speeds up page loading
+ * times by negating the need to switch locales on each page load.
+ *
+ * This is more inline with WP core behavior which does not localize slugs.
+ *
+ * @since 3.0.0
+ * @return array
+ */
+function wc_get_permalink_structure() {
+ $saved_permalinks = (array) get_option( 'woocommerce_permalinks', array() );
+ $permalinks = wp_parse_args(
+ array_filter( $saved_permalinks ),
+ array(
+ 'product_base' => _x( 'product', 'slug', 'woocommerce' ),
+ 'category_base' => _x( 'product-category', 'slug', 'woocommerce' ),
+ 'tag_base' => _x( 'product-tag', 'slug', 'woocommerce' ),
+ 'attribute_base' => '',
+ 'use_verbose_page_rules' => false,
+ )
+ );
+
+ if ( $saved_permalinks !== $permalinks ) {
+ update_option( 'woocommerce_permalinks', $permalinks );
+ }
+
+ $permalinks['product_rewrite_slug'] = untrailingslashit( $permalinks['product_base'] );
+ $permalinks['category_rewrite_slug'] = untrailingslashit( $permalinks['category_base'] );
+ $permalinks['tag_rewrite_slug'] = untrailingslashit( $permalinks['tag_base'] );
+ $permalinks['attribute_rewrite_slug'] = untrailingslashit( $permalinks['attribute_base'] );
+
+ return $permalinks;
+}
+
+/**
+ * Switch WooCommerce to site language.
+ *
+ * @since 3.1.0
+ */
+function wc_switch_to_site_locale() {
+ if ( function_exists( 'switch_to_locale' ) ) {
+ switch_to_locale( get_locale() );
+
+ // Filter on plugin_locale so load_plugin_textdomain loads the correct locale.
+ add_filter( 'plugin_locale', 'get_locale' );
+
+ // Init WC locale.
+ WC()->load_plugin_textdomain();
+ }
+}
+
+/**
+ * Switch WooCommerce language to original.
+ *
+ * @since 3.1.0
+ */
+function wc_restore_locale() {
+ if ( function_exists( 'restore_previous_locale' ) ) {
+ restore_previous_locale();
+
+ // Remove filter.
+ remove_filter( 'plugin_locale', 'get_locale' );
+
+ // Init WC locale.
+ WC()->load_plugin_textdomain();
+ }
+}
+
+/**
+ * Convert plaintext phone number to clickable phone number.
+ *
+ * Remove formatting and allow "+".
+ * Example and specs: https://developer.mozilla.org/en/docs/Web/HTML/Element/a#Creating_a_phone_link
+ *
+ * @since 3.1.0
+ *
+ * @param string $phone Content to convert phone number.
+ * @return string Content with converted phone number.
+ */
+function wc_make_phone_clickable( $phone ) {
+ $number = trim( preg_replace( '/[^\d|\+]/', '', $phone ) );
+
+ return $number ? '' . esc_html( $phone ) . '' : '';
+}
+
+/**
+ * Get an item of post data if set, otherwise return a default value.
+ *
+ * @since 3.0.9
+ * @param string $key Meta key.
+ * @param string $default Default value.
+ * @return mixed Value sanitized by wc_clean.
+ */
+function wc_get_post_data_by_key( $key, $default = '' ) {
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput, WordPress.Security.NonceVerification.Missing
+ return wc_clean( wp_unslash( wc_get_var( $_POST[ $key ], $default ) ) );
+}
+
+/**
+ * Get data if set, otherwise return a default value or null. Prevents notices when data is not set.
+ *
+ * @since 3.2.0
+ * @param mixed $var Variable.
+ * @param string $default Default value.
+ * @return mixed
+ */
+function wc_get_var( &$var, $default = null ) {
+ return isset( $var ) ? $var : $default;
+}
+
+/**
+ * Read in WooCommerce headers when reading plugin headers.
+ *
+ * @since 3.2.0
+ * @param array $headers Headers.
+ * @return array
+ */
+function wc_enable_wc_plugin_headers( $headers ) {
+ if ( ! class_exists( 'WC_Plugin_Updates' ) ) {
+ include_once dirname( __FILE__ ) . '/admin/plugin-updates/class-wc-plugin-updates.php';
+ }
+
+ // WC requires at least - allows developers to define which version of WooCommerce the plugin requires to run.
+ $headers[] = WC_Plugin_Updates::VERSION_REQUIRED_HEADER;
+
+ // WC tested up to - allows developers to define which version of WooCommerce they have tested up to.
+ $headers[] = WC_Plugin_Updates::VERSION_TESTED_HEADER;
+
+ // Woo - This is used in WooCommerce extensions and is picked up by the helper.
+ $headers[] = 'Woo';
+
+ return $headers;
+}
+add_filter( 'extra_theme_headers', 'wc_enable_wc_plugin_headers' );
+add_filter( 'extra_plugin_headers', 'wc_enable_wc_plugin_headers' );
+
+/**
+ * Prevent auto-updating the WooCommerce plugin on major releases if there are untested extensions active.
+ *
+ * @since 3.2.0
+ * @param bool $should_update If should update.
+ * @param object $plugin Plugin data.
+ * @return bool
+ */
+function wc_prevent_dangerous_auto_updates( $should_update, $plugin ) {
+ if ( ! isset( $plugin->plugin, $plugin->new_version ) ) {
+ return $should_update;
+ }
+
+ if ( 'woocommerce/woocommerce.php' !== $plugin->plugin ) {
+ return $should_update;
+ }
+
+ if ( ! class_exists( 'WC_Plugin_Updates' ) ) {
+ include_once dirname( __FILE__ ) . '/admin/plugin-updates/class-wc-plugin-updates.php';
+ }
+
+ $new_version = wc_clean( $plugin->new_version );
+ $plugin_updates = new WC_Plugin_Updates();
+ $untested_plugins = $plugin_updates->get_untested_plugins( $new_version, 'major' );
+ if ( ! empty( $untested_plugins ) ) {
+ return false;
+ }
+
+ return $should_update;
+}
+add_filter( 'auto_update_plugin', 'wc_prevent_dangerous_auto_updates', 99, 2 );
+
+/**
+ * Delete expired transients.
+ *
+ * Deletes all expired transients. The multi-table delete syntax is used.
+ * to delete the transient record from table a, and the corresponding.
+ * transient_timeout record from table b.
+ *
+ * Based on code inside core's upgrade_network() function.
+ *
+ * @since 3.2.0
+ * @return int Number of transients that were cleared.
+ */
+function wc_delete_expired_transients() {
+ global $wpdb;
+
+ // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
+ $sql = "DELETE a, b FROM $wpdb->options a, $wpdb->options b
+ WHERE a.option_name LIKE %s
+ AND a.option_name NOT LIKE %s
+ AND b.option_name = CONCAT( '_transient_timeout_', SUBSTRING( a.option_name, 12 ) )
+ AND b.option_value < %d";
+ $rows = $wpdb->query( $wpdb->prepare( $sql, $wpdb->esc_like( '_transient_' ) . '%', $wpdb->esc_like( '_transient_timeout_' ) . '%', time() ) );
+
+ $sql = "DELETE a, b FROM $wpdb->options a, $wpdb->options b
+ WHERE a.option_name LIKE %s
+ AND a.option_name NOT LIKE %s
+ AND b.option_name = CONCAT( '_site_transient_timeout_', SUBSTRING( a.option_name, 17 ) )
+ AND b.option_value < %d";
+ $rows2 = $wpdb->query( $wpdb->prepare( $sql, $wpdb->esc_like( '_site_transient_' ) . '%', $wpdb->esc_like( '_site_transient_timeout_' ) . '%', time() ) );
+ // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
+
+ return absint( $rows + $rows2 );
+}
+add_action( 'woocommerce_installed', 'wc_delete_expired_transients' );
+
+/**
+ * Make a URL relative, if possible.
+ *
+ * @since 3.2.0
+ * @param string $url URL to make relative.
+ * @return string
+ */
+function wc_get_relative_url( $url ) {
+ return wc_is_external_resource( $url ) ? $url : str_replace( array( 'http://', 'https://' ), '//', $url );
+}
+
+/**
+ * See if a resource is remote.
+ *
+ * @since 3.2.0
+ * @param string $url URL to check.
+ * @return bool
+ */
+function wc_is_external_resource( $url ) {
+ $wp_base = str_replace( array( 'http://', 'https://' ), '//', get_home_url( null, '/', 'http' ) );
+
+ return strstr( $url, '://' ) && ! strstr( $url, $wp_base );
+}
+
+/**
+ * See if theme/s is activate or not.
+ *
+ * @since 3.3.0
+ * @param string|array $theme Theme name or array of theme names to check.
+ * @return boolean
+ */
+function wc_is_active_theme( $theme ) {
+ return is_array( $theme ) ? in_array( get_template(), $theme, true ) : get_template() === $theme;
+}
+
+/**
+ * Is the site using a default WP theme?
+ *
+ * @return boolean
+ */
+function wc_is_wp_default_theme_active() {
+ return wc_is_active_theme(
+ array(
+ 'twentytwentyone',
+ 'twentytwenty',
+ 'twentynineteen',
+ 'twentyseventeen',
+ 'twentysixteen',
+ 'twentyfifteen',
+ 'twentyfourteen',
+ 'twentythirteen',
+ 'twentyeleven',
+ 'twentytwelve',
+ 'twentyten',
+ )
+ );
+}
+
+/**
+ * Cleans up session data - cron callback.
+ *
+ * @since 3.3.0
+ */
+function wc_cleanup_session_data() {
+ $session_class = apply_filters( 'woocommerce_session_handler', 'WC_Session_Handler' );
+ $session = new $session_class();
+
+ if ( is_callable( array( $session, 'cleanup_sessions' ) ) ) {
+ $session->cleanup_sessions();
+ }
+}
+add_action( 'woocommerce_cleanup_sessions', 'wc_cleanup_session_data' );
+
+/**
+ * Convert a decimal (e.g. 3.5) to a fraction (e.g. 7/2).
+ * From: https://www.designedbyaturtle.co.uk/2015/converting-a-decimal-to-a-fraction-in-php/
+ *
+ * @param float $decimal the decimal number.
+ * @return array|bool a 1/2 would be [1, 2] array (this can be imploded with '/' to form a string).
+ */
+function wc_decimal_to_fraction( $decimal ) {
+ if ( 0 > $decimal || ! is_numeric( $decimal ) ) {
+ // Negative digits need to be passed in as positive numbers and prefixed as negative once the response is imploded.
+ return false;
+ }
+
+ if ( 0 === $decimal ) {
+ return array( 0, 1 );
+ }
+
+ $tolerance = 1.e-4;
+ $numerator = 1;
+ $h2 = 0;
+ $denominator = 0;
+ $k2 = 1;
+ $b = 1 / $decimal;
+
+ do {
+ $b = 1 / $b;
+ $a = floor( $b );
+ $aux = $numerator;
+ $numerator = $a * $numerator + $h2;
+ $h2 = $aux;
+ $aux = $denominator;
+ $denominator = $a * $denominator + $k2;
+ $k2 = $aux;
+ $b = $b - $a;
+ } while ( abs( $decimal - $numerator / $denominator ) > $decimal * $tolerance );
+
+ return array( $numerator, $denominator );
+}
+
+/**
+ * Round discount.
+ *
+ * @param double $value Amount to round.
+ * @param int $precision DP to round.
+ * @return float
+ */
+function wc_round_discount( $value, $precision ) {
+ if ( version_compare( PHP_VERSION, '5.3.0', '>=' ) ) {
+ return NumberUtil::round( $value, $precision, WC_DISCOUNT_ROUNDING_MODE ); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctionParameters.round_modeFound
+ }
+
+ if ( 2 === WC_DISCOUNT_ROUNDING_MODE ) {
+ return wc_legacy_round_half_down( $value, $precision );
+ }
+
+ return NumberUtil::round( $value, $precision );
+}
+
+/**
+ * Return the html selected attribute if stringified $value is found in array of stringified $options
+ * or if stringified $value is the same as scalar stringified $options.
+ *
+ * @param string|int $value Value to find within options.
+ * @param string|int|array $options Options to go through when looking for value.
+ * @return string
+ */
+function wc_selected( $value, $options ) {
+ if ( is_array( $options ) ) {
+ $options = array_map( 'strval', $options );
+ return selected( in_array( (string) $value, $options, true ), true, false );
+ }
+
+ return selected( $value, $options, false );
+}
+
+/**
+ * Retrieves the MySQL server version. Based on $wpdb.
+ *
+ * @since 3.4.1
+ * @return array Vesion information.
+ */
+function wc_get_server_database_version() {
+ global $wpdb;
+
+ if ( empty( $wpdb->is_mysql ) ) {
+ return array(
+ 'string' => '',
+ 'number' => '',
+ );
+ }
+
+ // phpcs:disable WordPress.DB.RestrictedFunctions, PHPCompatibility.Extensions.RemovedExtensions.mysql_DeprecatedRemoved
+ if ( $wpdb->use_mysqli ) {
+ $server_info = mysqli_get_server_info( $wpdb->dbh );
+ } else {
+ $server_info = mysql_get_server_info( $wpdb->dbh );
+ }
+ // phpcs:enable WordPress.DB.RestrictedFunctions, PHPCompatibility.Extensions.RemovedExtensions.mysql_DeprecatedRemoved
+
+ return array(
+ 'string' => $server_info,
+ 'number' => preg_replace( '/([^\d.]+).*/', '', $server_info ),
+ );
+}
+
+/**
+ * Initialize and load the cart functionality.
+ *
+ * @since 3.6.4
+ * @return void
+ */
+function wc_load_cart() {
+ if ( ! did_action( 'before_woocommerce_init' ) || doing_action( 'before_woocommerce_init' ) ) {
+ /* translators: 1: wc_load_cart 2: woocommerce_init */
+ wc_doing_it_wrong( __FUNCTION__, sprintf( __( '%1$s should not be called before the %2$s action.', 'woocommerce' ), 'wc_load_cart', 'woocommerce_init' ), '3.7' );
+ return;
+ }
+
+ // Ensure dependencies are loaded in all contexts.
+ include_once WC_ABSPATH . 'includes/wc-cart-functions.php';
+ include_once WC_ABSPATH . 'includes/wc-notice-functions.php';
+
+ WC()->initialize_session();
+ WC()->initialize_cart();
+}
+
+/**
+ * Test whether the context of execution comes from async action scheduler.
+ *
+ * @since 4.0.0
+ * @return bool
+ */
+function wc_is_running_from_async_action_scheduler() {
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ return isset( $_REQUEST['action'] ) && 'as_async_request_queue_runner' === $_REQUEST['action'];
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-coupon-functions.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-coupon-functions.php
new file mode 100644
index 0000000..28ef64a
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-coupon-functions.php
@@ -0,0 +1,111 @@
+ __( 'Percentage discount', 'woocommerce' ),
+ 'fixed_cart' => __( 'Fixed cart discount', 'woocommerce' ),
+ 'fixed_product' => __( 'Fixed product discount', 'woocommerce' ),
+ )
+ );
+}
+
+/**
+ * Get a coupon type's name.
+ *
+ * @param string $type Coupon type.
+ * @return string
+ */
+function wc_get_coupon_type( $type = '' ) {
+ $types = wc_get_coupon_types();
+ return isset( $types[ $type ] ) ? $types[ $type ] : '';
+}
+
+/**
+ * Coupon types that apply to individual products. Controls which validation rules will apply.
+ *
+ * @since 2.5.0
+ * @return array
+ */
+function wc_get_product_coupon_types() {
+ return (array) apply_filters( 'woocommerce_product_coupon_types', array( 'fixed_product', 'percent' ) );
+}
+
+/**
+ * Coupon types that apply to the cart as a whole. Controls which validation rules will apply.
+ *
+ * @since 2.5.0
+ * @return array
+ */
+function wc_get_cart_coupon_types() {
+ return (array) apply_filters( 'woocommerce_cart_coupon_types', array( 'fixed_cart' ) );
+}
+
+/**
+ * Check if coupons are enabled.
+ * Filterable.
+ *
+ * @since 2.5.0
+ *
+ * @return bool
+ */
+function wc_coupons_enabled() {
+ return apply_filters( 'woocommerce_coupons_enabled', 'yes' === get_option( 'woocommerce_enable_coupons' ) );
+}
+
+/**
+ * Get coupon code by ID.
+ *
+ * @since 3.0.0
+ * @param int $id Coupon ID.
+ * @return string
+ */
+function wc_get_coupon_code_by_id( $id ) {
+ $data_store = WC_Data_Store::load( 'coupon' );
+ return empty( $id ) ? '' : (string) $data_store->get_code_by_id( $id );
+}
+
+/**
+ * Get coupon ID by code.
+ *
+ * @since 3.0.0
+ * @param string $code Coupon code.
+ * @param int $exclude Used to exclude an ID from the check if you're checking existence.
+ * @return int
+ */
+function wc_get_coupon_id_by_code( $code, $exclude = 0 ) {
+
+ if ( empty( $code ) ) {
+ return 0;
+ }
+
+ $data_store = WC_Data_Store::load( 'coupon' );
+ $ids = wp_cache_get( WC_Cache_Helper::get_cache_prefix( 'coupons' ) . 'coupon_id_from_code_' . $code, 'coupons' );
+
+ if ( false === $ids ) {
+ $ids = $data_store->get_ids_by_code( $code );
+ if ( $ids ) {
+ wp_cache_set( WC_Cache_Helper::get_cache_prefix( 'coupons' ) . 'coupon_id_from_code_' . $code, $ids, 'coupons' );
+ }
+ }
+
+ $ids = array_diff( array_filter( array_map( 'absint', (array) $ids ) ), array( $exclude ) );
+
+ return apply_filters( 'woocommerce_get_coupon_id_from_code', absint( current( $ids ) ), $code, $exclude );
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-deprecated-functions.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-deprecated-functions.php
new file mode 100644
index 0000000..ea5f57f
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-deprecated-functions.php
@@ -0,0 +1,1125 @@
+is_rest_api_request() ) {
+ do_action( 'deprecated_function_run', $function, $replacement, $version );
+ $log_string = "The {$function} function is deprecated since version {$version}.";
+ $log_string .= $replacement ? " Replace with {$replacement}." : '';
+ error_log( $log_string );
+ } else {
+ _deprecated_function( $function, $version, $replacement );
+ }
+ // @codingStandardsIgnoreEnd
+}
+
+/**
+ * Wrapper for deprecated hook so we can apply some extra logic.
+ *
+ * @since 3.3.0
+ * @param string $hook The hook that was used.
+ * @param string $version The version of WordPress that deprecated the hook.
+ * @param string $replacement The hook that should have been used.
+ * @param string $message A message regarding the change.
+ */
+function wc_deprecated_hook( $hook, $version, $replacement = null, $message = null ) {
+ // @codingStandardsIgnoreStart
+ if ( is_ajax() || WC()->is_rest_api_request() ) {
+ do_action( 'deprecated_hook_run', $hook, $replacement, $version, $message );
+
+ $message = empty( $message ) ? '' : ' ' . $message;
+ $log_string = "{$hook} is deprecated since version {$version}";
+ $log_string .= $replacement ? "! Use {$replacement} instead." : ' with no alternative available.';
+
+ error_log( $log_string . $message );
+ } else {
+ _deprecated_hook( $hook, $version, $replacement, $message );
+ }
+ // @codingStandardsIgnoreEnd
+}
+
+/**
+ * When catching an exception, this allows us to log it if unexpected.
+ *
+ * @since 3.3.0
+ * @param Exception $exception_object The exception object.
+ * @param string $function The function which threw exception.
+ * @param array $args The args passed to the function.
+ */
+function wc_caught_exception( $exception_object, $function = '', $args = array() ) {
+ // @codingStandardsIgnoreStart
+ $message = $exception_object->getMessage();
+ $message .= '. Args: ' . print_r( $args, true ) . '.';
+
+ do_action( 'woocommerce_caught_exception', $exception_object, $function, $args );
+ error_log( "Exception caught in {$function}. {$message}." );
+ // @codingStandardsIgnoreEnd
+}
+
+/**
+ * Wrapper for _doing_it_wrong().
+ *
+ * @since 3.0.0
+ * @param string $function Function used.
+ * @param string $message Message to log.
+ * @param string $version Version the message was added in.
+ */
+function wc_doing_it_wrong( $function, $message, $version ) {
+ // @codingStandardsIgnoreStart
+ $message .= ' Backtrace: ' . wp_debug_backtrace_summary();
+
+ if ( is_ajax() || WC()->is_rest_api_request() ) {
+ do_action( 'doing_it_wrong_run', $function, $message, $version );
+ error_log( "{$function} was called incorrectly. {$message}. This message was added in version {$version}." );
+ } else {
+ _doing_it_wrong( $function, $message, $version );
+ }
+ // @codingStandardsIgnoreEnd
+}
+
+/**
+ * Wrapper for deprecated arguments so we can apply some extra logic.
+ *
+ * @since 3.0.0
+ * @param string $argument
+ * @param string $version
+ * @param string $replacement
+ */
+function wc_deprecated_argument( $argument, $version, $message = null ) {
+ if ( is_ajax() || WC()->is_rest_api_request() ) {
+ do_action( 'deprecated_argument_run', $argument, $message, $version );
+ error_log( "The {$argument} argument is deprecated since version {$version}. {$message}" );
+ } else {
+ _deprecated_argument( $argument, $version, $message );
+ }
+}
+
+/**
+ * @deprecated 2.1
+ */
+function woocommerce_show_messages() {
+ wc_deprecated_function( 'woocommerce_show_messages', '2.1', 'wc_print_notices' );
+ wc_print_notices();
+}
+
+/**
+ * @deprecated 2.1
+ */
+function woocommerce_weekend_area_js() {
+ wc_deprecated_function( 'woocommerce_weekend_area_js', '2.1' );
+}
+
+/**
+ * @deprecated 2.1
+ */
+function woocommerce_tooltip_js() {
+ wc_deprecated_function( 'woocommerce_tooltip_js', '2.1' );
+}
+
+/**
+ * @deprecated 2.1
+ */
+function woocommerce_datepicker_js() {
+ wc_deprecated_function( 'woocommerce_datepicker_js', '2.1' );
+}
+
+/**
+ * @deprecated 2.1
+ */
+function woocommerce_admin_scripts() {
+ wc_deprecated_function( 'woocommerce_admin_scripts', '2.1' );
+}
+
+/**
+ * @deprecated 2.1
+ */
+function woocommerce_create_page( $slug, $option = '', $page_title = '', $page_content = '', $post_parent = 0 ) {
+ wc_deprecated_function( 'woocommerce_create_page', '2.1', 'wc_create_page' );
+ return wc_create_page( $slug, $option, $page_title, $page_content, $post_parent );
+}
+
+/**
+ * @deprecated 2.1
+ */
+function woocommerce_readfile_chunked( $file, $retbytes = true ) {
+ wc_deprecated_function( 'woocommerce_readfile_chunked', '2.1', 'WC_Download_Handler::readfile_chunked()' );
+ return WC_Download_Handler::readfile_chunked( $file );
+}
+
+/**
+ * Formal total costs - format to the number of decimal places for the base currency.
+ *
+ * @access public
+ * @param mixed $number
+ * @deprecated 2.1
+ * @return string
+ */
+function woocommerce_format_total( $number ) {
+ wc_deprecated_function( __FUNCTION__, '2.1', 'wc_format_decimal()' );
+ return wc_format_decimal( $number, wc_get_price_decimals(), false );
+}
+
+/**
+ * Get product name with extra details such as SKU price and attributes. Used within admin.
+ *
+ * @access public
+ * @param WC_Product $product
+ * @deprecated 2.1
+ * @return string
+ */
+function woocommerce_get_formatted_product_name( $product ) {
+ wc_deprecated_function( __FUNCTION__, '2.1', 'WC_Product::get_formatted_name()' );
+ return $product->get_formatted_name();
+}
+
+/**
+ * Handle IPN requests for the legacy paypal gateway by calling gateways manually if needed.
+ *
+ * @access public
+ */
+function woocommerce_legacy_paypal_ipn() {
+ if ( ! empty( $_GET['paypalListener'] ) && 'paypal_standard_IPN' === $_GET['paypalListener'] ) {
+ WC()->payment_gateways();
+ do_action( 'woocommerce_api_wc_gateway_paypal' );
+ }
+}
+add_action( 'init', 'woocommerce_legacy_paypal_ipn' );
+
+/**
+ * @deprecated 3.0
+ */
+function get_product( $the_product = false, $args = array() ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_product' );
+ return wc_get_product( $the_product, $args );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_protected_product_add_to_cart( $passed, $product_id ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_protected_product_add_to_cart' );
+ return wc_protected_product_add_to_cart( $passed, $product_id );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_empty_cart() {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_empty_cart' );
+ wc_empty_cart();
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_load_persistent_cart( $user_login, $user = 0 ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_load_persistent_cart' );
+ return wc_load_persistent_cart( $user_login, $user );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_add_to_cart_message( $product_id ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_add_to_cart_message' );
+ wc_add_to_cart_message( $product_id );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_clear_cart_after_payment() {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_clear_cart_after_payment' );
+ wc_clear_cart_after_payment();
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_cart_totals_subtotal_html() {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_cart_totals_subtotal_html' );
+ wc_cart_totals_subtotal_html();
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_cart_totals_shipping_html() {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_cart_totals_shipping_html' );
+ wc_cart_totals_shipping_html();
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_cart_totals_coupon_html( $coupon ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_cart_totals_coupon_html' );
+ wc_cart_totals_coupon_html( $coupon );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_cart_totals_order_total_html() {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_cart_totals_order_total_html' );
+ wc_cart_totals_order_total_html();
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_cart_totals_fee_html( $fee ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_cart_totals_fee_html' );
+ wc_cart_totals_fee_html( $fee );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_cart_totals_shipping_method_label( $method ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_cart_totals_shipping_method_label' );
+ return wc_cart_totals_shipping_method_label( $method );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_get_template_part( $slug, $name = '' ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_template_part' );
+ wc_get_template_part( $slug, $name );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_get_template( $template_name, $args = array(), $template_path = '', $default_path = '' ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_template' );
+ wc_get_template( $template_name, $args, $template_path, $default_path );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_locate_template( $template_name, $template_path = '', $default_path = '' ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_locate_template' );
+ return wc_locate_template( $template_name, $template_path, $default_path );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_mail( $to, $subject, $message, $headers = "Content-Type: text/html\r\n", $attachments = "" ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_mail' );
+ wc_mail( $to, $subject, $message, $headers, $attachments );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_disable_admin_bar( $show_admin_bar ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_disable_admin_bar' );
+ return wc_disable_admin_bar( $show_admin_bar );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_create_new_customer( $email, $username = '', $password = '' ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_create_new_customer' );
+ return wc_create_new_customer( $email, $username, $password );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_set_customer_auth_cookie( $customer_id ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_set_customer_auth_cookie' );
+ wc_set_customer_auth_cookie( $customer_id );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_update_new_customer_past_orders( $customer_id ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_update_new_customer_past_orders' );
+ return wc_update_new_customer_past_orders( $customer_id );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_paying_customer( $order_id ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_paying_customer' );
+ wc_paying_customer( $order_id );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_customer_bought_product( $customer_email, $user_id, $product_id ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_customer_bought_product' );
+ return wc_customer_bought_product( $customer_email, $user_id, $product_id );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_customer_has_capability( $allcaps, $caps, $args ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_customer_has_capability' );
+ return wc_customer_has_capability( $allcaps, $caps, $args );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_sanitize_taxonomy_name( $taxonomy ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_sanitize_taxonomy_name' );
+ return wc_sanitize_taxonomy_name( $taxonomy );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_get_filename_from_url( $file_url ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_filename_from_url' );
+ return wc_get_filename_from_url( $file_url );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_get_dimension( $dim, $to_unit ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_dimension' );
+ return wc_get_dimension( $dim, $to_unit );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_get_weight( $weight, $to_unit ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_weight' );
+ return wc_get_weight( $weight, $to_unit );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_trim_zeros( $price ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_trim_zeros' );
+ return wc_trim_zeros( $price );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_round_tax_total( $tax ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_round_tax_total' );
+ return wc_round_tax_total( $tax );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_format_decimal( $number, $dp = false, $trim_zeros = false ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_format_decimal' );
+ return wc_format_decimal( $number, $dp, $trim_zeros );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_clean( $var ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_clean' );
+ return wc_clean( $var );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_array_overlay( $a1, $a2 ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_array_overlay' );
+ return wc_array_overlay( $a1, $a2 );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_price( $price, $args = array() ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_price' );
+ return wc_price( $price, $args );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_let_to_num( $size ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_let_to_num' );
+ return wc_let_to_num( $size );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_date_format() {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_date_format' );
+ return wc_date_format();
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_time_format() {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_time_format' );
+ return wc_time_format();
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_timezone_string() {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_timezone_string' );
+ return wc_timezone_string();
+}
+
+if ( ! function_exists( 'woocommerce_rgb_from_hex' ) ) {
+ /**
+ * @deprecated 3.0
+ */
+ function woocommerce_rgb_from_hex( $color ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_rgb_from_hex' );
+ return wc_rgb_from_hex( $color );
+ }
+}
+
+if ( ! function_exists( 'woocommerce_hex_darker' ) ) {
+ /**
+ * @deprecated 3.0
+ */
+ function woocommerce_hex_darker( $color, $factor = 30 ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_hex_darker' );
+ return wc_hex_darker( $color, $factor );
+ }
+}
+
+if ( ! function_exists( 'woocommerce_hex_lighter' ) ) {
+ /**
+ * @deprecated 3.0
+ */
+ function woocommerce_hex_lighter( $color, $factor = 30 ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_hex_lighter' );
+ return wc_hex_lighter( $color, $factor );
+ }
+}
+
+if ( ! function_exists( 'woocommerce_light_or_dark' ) ) {
+ /**
+ * @deprecated 3.0
+ */
+ function woocommerce_light_or_dark( $color, $dark = '#000000', $light = '#FFFFFF' ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_light_or_dark' );
+ return wc_light_or_dark( $color, $dark, $light );
+ }
+}
+
+if ( ! function_exists( 'woocommerce_format_hex' ) ) {
+ /**
+ * @deprecated 3.0
+ */
+ function woocommerce_format_hex( $hex ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_format_hex' );
+ return wc_format_hex( $hex );
+ }
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_get_order_id_by_order_key( $order_key ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_order_id_by_order_key' );
+ return wc_get_order_id_by_order_key( $order_key );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_downloadable_file_permission( $download_id, $product_id, $order ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_downloadable_file_permission' );
+ return wc_downloadable_file_permission( $download_id, $product_id, $order );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_downloadable_product_permissions( $order_id ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_downloadable_product_permissions' );
+ wc_downloadable_product_permissions( $order_id );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_add_order_item( $order_id, $item ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_add_order_item' );
+ return wc_add_order_item( $order_id, $item );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_delete_order_item( $item_id ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_delete_order_item' );
+ return wc_delete_order_item( $item_id );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_update_order_item_meta( $item_id, $meta_key, $meta_value, $prev_value = '' ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_update_order_item_meta' );
+ return wc_update_order_item_meta( $item_id, $meta_key, $meta_value, $prev_value );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_add_order_item_meta( $item_id, $meta_key, $meta_value, $unique = false ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_add_order_item_meta' );
+ return wc_add_order_item_meta( $item_id, $meta_key, $meta_value, $unique );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_delete_order_item_meta( $item_id, $meta_key, $meta_value = '', $delete_all = false ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_delete_order_item_meta' );
+ return wc_delete_order_item_meta( $item_id, $meta_key, $meta_value, $delete_all );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_get_order_item_meta( $item_id, $key, $single = true ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_order_item_meta' );
+ return wc_get_order_item_meta( $item_id, $key, $single );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_cancel_unpaid_orders() {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_cancel_unpaid_orders' );
+ wc_cancel_unpaid_orders();
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_processing_order_count() {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_processing_order_count' );
+ return wc_processing_order_count();
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_get_page_id( $page ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_page_id' );
+ return wc_get_page_id( $page );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_get_endpoint_url( $endpoint, $value = '', $permalink = '' ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_endpoint_url' );
+ return wc_get_endpoint_url( $endpoint, $value, $permalink );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_lostpassword_url( $url ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_lostpassword_url' );
+ return wc_lostpassword_url( $url );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_customer_edit_account_url() {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_customer_edit_account_url' );
+ return wc_customer_edit_account_url();
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_nav_menu_items( $items, $args ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_nav_menu_items' );
+ return wc_nav_menu_items( $items );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_nav_menu_item_classes( $menu_items, $args ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_nav_menu_item_classes' );
+ return wc_nav_menu_item_classes( $menu_items );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_list_pages( $pages ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_list_pages' );
+ return wc_list_pages( $pages );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_product_dropdown_categories( $args = array(), $deprecated_hierarchical = 1, $deprecated_show_uncategorized = 1, $deprecated_orderby = '' ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_product_dropdown_categories' );
+ return wc_product_dropdown_categories( $args, $deprecated_hierarchical, $deprecated_show_uncategorized, $deprecated_orderby );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_walk_category_dropdown_tree( $a1 = '', $a2 = '', $a3 = '' ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_walk_category_dropdown_tree' );
+ return wc_walk_category_dropdown_tree( $a1, $a2, $a3 );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_taxonomy_metadata_wpdbfix() {
+ wc_deprecated_function( __FUNCTION__, '3.0' );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function wc_taxonomy_metadata_wpdbfix() {
+ wc_deprecated_function( __FUNCTION__, '3.0' );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_order_terms( $the_term, $next_id, $taxonomy, $index = 0, $terms = null ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_reorder_terms' );
+ return wc_reorder_terms( $the_term, $next_id, $taxonomy, $index, $terms );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_set_term_order( $term_id, $index, $taxonomy, $recursive = false ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_set_term_order' );
+ return wc_set_term_order( $term_id, $index, $taxonomy, $recursive );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_terms_clauses( $clauses, $taxonomies, $args ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_terms_clauses' );
+ return wc_terms_clauses( $clauses, $taxonomies, $args );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function _woocommerce_term_recount( $terms, $taxonomy, $callback, $terms_are_term_taxonomy_ids ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', '_wc_term_recount' );
+ return _wc_term_recount( $terms, $taxonomy, $callback, $terms_are_term_taxonomy_ids );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_recount_after_stock_change( $product_id ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_recount_after_stock_change' );
+ return wc_recount_after_stock_change( $product_id );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_change_term_counts( $terms, $taxonomies, $args ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_change_term_counts' );
+ return wc_change_term_counts( $terms, $taxonomies );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_get_product_ids_on_sale() {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_product_ids_on_sale' );
+ return wc_get_product_ids_on_sale();
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_get_featured_product_ids() {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_featured_product_ids' );
+ return wc_get_featured_product_ids();
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_get_product_terms( $object_id, $taxonomy, $fields = 'all' ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_product_terms' );
+ return wc_get_product_terms( $object_id, $taxonomy, array( 'fields' => $fields ) );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_product_post_type_link( $permalink, $post ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_product_post_type_link' );
+ return wc_product_post_type_link( $permalink, $post );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_placeholder_img_src() {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_placeholder_img_src' );
+ return wc_placeholder_img_src();
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_placeholder_img( $size = 'woocommerce_thumbnail' ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_placeholder_img' );
+ return wc_placeholder_img( $size );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_get_formatted_variation( $variation = '', $flat = false ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_formatted_variation' );
+ return wc_get_formatted_variation( $variation, $flat );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_scheduled_sales() {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_scheduled_sales' );
+ return wc_scheduled_sales();
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_get_attachment_image_attributes( $attr ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_get_attachment_image_attributes' );
+ return wc_get_attachment_image_attributes( $attr );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_prepare_attachment_for_js( $response ) {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_prepare_attachment_for_js' );
+ return wc_prepare_attachment_for_js( $response );
+}
+
+/**
+ * @deprecated 3.0
+ */
+function woocommerce_track_product_view() {
+ wc_deprecated_function( __FUNCTION__, '3.0', 'wc_track_product_view' );
+ return wc_track_product_view();
+}
+
+/**
+ * @deprecated 2.3 has no replacement
+ */
+function woocommerce_compile_less_styles() {
+ wc_deprecated_function( 'woocommerce_compile_less_styles', '2.3' );
+}
+
+/**
+ * woocommerce_calc_shipping was an option used to determine if shipping was enabled prior to version 2.6.0. This has since been replaced with wc_shipping_enabled() function and
+ * the woocommerce_ship_to_countries setting.
+ * @deprecated 2.6.0
+ * @return string
+ */
+function woocommerce_calc_shipping_backwards_compatibility( $value ) {
+ if ( Constants::is_defined( 'WC_UPDATING' ) ) {
+ return $value;
+ }
+ return 'disabled' === get_option( 'woocommerce_ship_to_countries' ) ? 'no' : 'yes';
+}
+add_filter( 'pre_option_woocommerce_calc_shipping', 'woocommerce_calc_shipping_backwards_compatibility' );
+
+/**
+ * @deprecated 3.0.0
+ * @see WC_Structured_Data class
+ *
+ * @return string
+ */
+function woocommerce_get_product_schema() {
+ wc_deprecated_function( 'woocommerce_get_product_schema', '3.0' );
+
+ global $product;
+
+ $schema = "Product";
+
+ // Downloadable product schema handling
+ if ( $product->is_downloadable() ) {
+ switch ( $product->download_type ) {
+ case 'application' :
+ $schema = "SoftwareApplication";
+ break;
+ case 'music' :
+ $schema = "MusicAlbum";
+ break;
+ default :
+ $schema = "Product";
+ break;
+ }
+ }
+
+ return 'http://schema.org/' . $schema;
+}
+
+/**
+ * Save product price.
+ *
+ * This is a private function (internal use ONLY) used until a data manipulation api is built.
+ *
+ * @deprecated 3.0.0
+ * @param int $product_id
+ * @param float $regular_price
+ * @param float $sale_price
+ * @param string $date_from
+ * @param string $date_to
+ */
+function _wc_save_product_price( $product_id, $regular_price, $sale_price = '', $date_from = '', $date_to = '' ) {
+ wc_doing_it_wrong( '_wc_save_product_price()', 'This function is not for developer use and is deprecated.', '3.0' );
+
+ $product_id = absint( $product_id );
+ $regular_price = wc_format_decimal( $regular_price );
+ $sale_price = '' === $sale_price ? '' : wc_format_decimal( $sale_price );
+ $date_from = wc_clean( $date_from );
+ $date_to = wc_clean( $date_to );
+
+ update_post_meta( $product_id, '_regular_price', $regular_price );
+ update_post_meta( $product_id, '_sale_price', $sale_price );
+
+ // Save Dates
+ update_post_meta( $product_id, '_sale_price_dates_from', $date_from ? strtotime( $date_from ) : '' );
+ update_post_meta( $product_id, '_sale_price_dates_to', $date_to ? strtotime( $date_to ) : '' );
+
+ if ( $date_to && ! $date_from ) {
+ $date_from = strtotime( 'NOW', current_time( 'timestamp' ) );
+ update_post_meta( $product_id, '_sale_price_dates_from', $date_from );
+ }
+
+ // Update price if on sale
+ if ( '' !== $sale_price && '' === $date_to && '' === $date_from ) {
+ update_post_meta( $product_id, '_price', $sale_price );
+ } else {
+ update_post_meta( $product_id, '_price', $regular_price );
+ }
+
+ if ( '' !== $sale_price && $date_from && strtotime( $date_from ) < strtotime( 'NOW', current_time( 'timestamp' ) ) ) {
+ update_post_meta( $product_id, '_price', $sale_price );
+ }
+
+ if ( $date_to && strtotime( $date_to ) < strtotime( 'NOW', current_time( 'timestamp' ) ) ) {
+ update_post_meta( $product_id, '_price', $regular_price );
+ update_post_meta( $product_id, '_sale_price_dates_from', '' );
+ update_post_meta( $product_id, '_sale_price_dates_to', '' );
+ }
+}
+
+/**
+ * Return customer avatar URL.
+ *
+ * @deprecated 3.1.0
+ * @since 2.6.0
+ * @param string $email the customer's email.
+ * @return string the URL to the customer's avatar.
+ */
+function wc_get_customer_avatar_url( $email ) {
+ // Deprecated in favor of WordPress get_avatar_url() function.
+ wc_deprecated_function( 'wc_get_customer_avatar_url()', '3.1', 'get_avatar_url()' );
+
+ return get_avatar_url( $email );
+}
+
+/**
+ * WooCommerce Core Supported Themes.
+ *
+ * @deprecated 3.3.0
+ * @since 2.2
+ * @return string[]
+ */
+function wc_get_core_supported_themes() {
+ wc_deprecated_function( 'wc_get_core_supported_themes()', '3.3' );
+ return array( 'twentyseventeen', 'twentysixteen', 'twentyfifteen', 'twentyfourteen', 'twentythirteen', 'twentyeleven', 'twentytwelve', 'twentyten' );
+}
+
+/**
+ * Get min/max price meta query args.
+ *
+ * @deprecated 3.6.0
+ * @since 3.0.0
+ * @param array $args Min price and max price arguments.
+ * @return array
+ */
+function wc_get_min_max_price_meta_query( $args ) {
+ wc_deprecated_function( 'wc_get_min_max_price_meta_query()', '3.6' );
+
+ $current_min_price = isset( $args['min_price'] ) ? floatval( $args['min_price'] ) : 0;
+ $current_max_price = isset( $args['max_price'] ) ? floatval( $args['max_price'] ) : PHP_INT_MAX;
+
+ return apply_filters(
+ 'woocommerce_get_min_max_price_meta_query',
+ array(
+ 'key' => '_price',
+ 'value' => array( $current_min_price, $current_max_price ),
+ 'compare' => 'BETWEEN',
+ 'type' => 'DECIMAL(10,' . wc_get_price_decimals() . ')',
+ ),
+ $args
+ );
+}
+
+/**
+ * When a term is split, ensure meta data maintained.
+ *
+ * @deprecated 3.6.0
+ * @param int $old_term_id Old term ID.
+ * @param int $new_term_id New term ID.
+ * @param string $term_taxonomy_id Term taxonomy ID.
+ * @param string $taxonomy Taxonomy.
+ */
+function wc_taxonomy_metadata_update_content_for_split_terms( $old_term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
+ wc_deprecated_function( 'wc_taxonomy_metadata_update_content_for_split_terms', '3.6' );
+}
+
+/**
+ * WooCommerce Term Meta API.
+ *
+ * WC tables for storing term meta are deprecated from WordPress 4.4 since 4.4 has its own table.
+ * This function serves as a wrapper, using the new table if present, or falling back to the WC table.
+ *
+ * @deprecated 3.6.0
+ * @param int $term_id Term ID.
+ * @param string $meta_key Meta key.
+ * @param mixed $meta_value Meta value.
+ * @param string $prev_value Previous value. (default: '').
+ * @return bool
+ */
+function update_woocommerce_term_meta( $term_id, $meta_key, $meta_value, $prev_value = '' ) {
+ wc_deprecated_function( 'update_woocommerce_term_meta', '3.6', 'update_term_meta' );
+ return function_exists( 'update_term_meta' ) ? update_term_meta( $term_id, $meta_key, $meta_value, $prev_value ) : update_metadata( 'woocommerce_term', $term_id, $meta_key, $meta_value, $prev_value );
+}
+
+/**
+ * WooCommerce Term Meta API.
+ *
+ * WC tables for storing term meta are deprecated from WordPress 4.4 since 4.4 has its own table.
+ * This function serves as a wrapper, using the new table if present, or falling back to the WC table.
+ *
+ * @deprecated 3.6.0
+ * @param int $term_id Term ID.
+ * @param string $meta_key Meta key.
+ * @param mixed $meta_value Meta value.
+ * @param bool $unique Make meta key unique. (default: false).
+ * @return bool
+ */
+function add_woocommerce_term_meta( $term_id, $meta_key, $meta_value, $unique = false ) {
+ wc_deprecated_function( 'add_woocommerce_term_meta', '3.6', 'add_term_meta' );
+ return function_exists( 'add_term_meta' ) ? add_term_meta( $term_id, $meta_key, $meta_value, $unique ) : add_metadata( 'woocommerce_term', $term_id, $meta_key, $meta_value, $unique );
+}
+
+/**
+ * WooCommerce Term Meta API
+ *
+ * WC tables for storing term meta are deprecated from WordPress 4.4 since 4.4 has its own table.
+ * This function serves as a wrapper, using the new table if present, or falling back to the WC table.
+ *
+ * @deprecated 3.6.0
+ * @param int $term_id Term ID.
+ * @param string $meta_key Meta key.
+ * @param string $meta_value Meta value (default: '').
+ * @param bool $deprecated Deprecated param (default: false).
+ * @return bool
+ */
+function delete_woocommerce_term_meta( $term_id, $meta_key, $meta_value = '', $deprecated = false ) {
+ wc_deprecated_function( 'delete_woocommerce_term_meta', '3.6', 'delete_term_meta' );
+ return function_exists( 'delete_term_meta' ) ? delete_term_meta( $term_id, $meta_key, $meta_value ) : delete_metadata( 'woocommerce_term', $term_id, $meta_key, $meta_value );
+}
+
+/**
+ * WooCommerce Term Meta API
+ *
+ * WC tables for storing term meta are deprecated from WordPress 4.4 since 4.4 has its own table.
+ * This function serves as a wrapper, using the new table if present, or falling back to the WC table.
+ *
+ * @deprecated 3.6.0
+ * @param int $term_id Term ID.
+ * @param string $key Meta key.
+ * @param bool $single Whether to return a single value. (default: true).
+ * @return mixed
+ */
+function get_woocommerce_term_meta( $term_id, $key, $single = true ) {
+ wc_deprecated_function( 'get_woocommerce_term_meta', '3.6', 'get_term_meta' );
+ return function_exists( 'get_term_meta' ) ? get_term_meta( $term_id, $key, $single ) : get_metadata( 'woocommerce_term', $term_id, $key, $single );
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-formatting-functions.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-formatting-functions.php
new file mode 100644
index 0000000..51a60e7
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-formatting-functions.php
@@ -0,0 +1,1481 @@
+strip_invalid_text_for_column( $wpdb->options, 'option_value', $value );
+
+ if ( is_wp_error( $value ) ) {
+ $value = '';
+ }
+
+ $value = esc_url_raw( trim( $value ) );
+ $value = str_replace( 'http://', '', $value );
+ return untrailingslashit( $value );
+}
+
+/**
+ * Gets the filename part of a download URL.
+ *
+ * @param string $file_url File URL.
+ * @return string
+ */
+function wc_get_filename_from_url( $file_url ) {
+ $parts = wp_parse_url( $file_url );
+ if ( isset( $parts['path'] ) ) {
+ return basename( $parts['path'] );
+ }
+}
+
+/**
+ * Normalise dimensions, unify to cm then convert to wanted unit value.
+ *
+ * Usage:
+ * wc_get_dimension( 55, 'in' );
+ * wc_get_dimension( 55, 'in', 'm' );
+ *
+ * @param int|float $dimension Dimension.
+ * @param string $to_unit Unit to convert to.
+ * Options: 'in', 'm', 'cm', 'm'.
+ * @param string $from_unit Unit to convert from.
+ * Defaults to ''.
+ * Options: 'in', 'm', 'cm', 'm'.
+ * @return float
+ */
+function wc_get_dimension( $dimension, $to_unit, $from_unit = '' ) {
+ $to_unit = strtolower( $to_unit );
+
+ if ( empty( $from_unit ) ) {
+ $from_unit = strtolower( get_option( 'woocommerce_dimension_unit' ) );
+ }
+
+ // Unify all units to cm first.
+ if ( $from_unit !== $to_unit ) {
+ switch ( $from_unit ) {
+ case 'in':
+ $dimension *= 2.54;
+ break;
+ case 'm':
+ $dimension *= 100;
+ break;
+ case 'mm':
+ $dimension *= 0.1;
+ break;
+ case 'yd':
+ $dimension *= 91.44;
+ break;
+ }
+
+ // Output desired unit.
+ switch ( $to_unit ) {
+ case 'in':
+ $dimension *= 0.3937;
+ break;
+ case 'm':
+ $dimension *= 0.01;
+ break;
+ case 'mm':
+ $dimension *= 10;
+ break;
+ case 'yd':
+ $dimension *= 0.010936133;
+ break;
+ }
+ }
+
+ return ( $dimension < 0 ) ? 0 : $dimension;
+}
+
+/**
+ * Normalise weights, unify to kg then convert to wanted unit value.
+ *
+ * Usage:
+ * wc_get_weight(55, 'kg');
+ * wc_get_weight(55, 'kg', 'lbs');
+ *
+ * @param int|float $weight Weight.
+ * @param string $to_unit Unit to convert to.
+ * Options: 'g', 'kg', 'lbs', 'oz'.
+ * @param string $from_unit Unit to convert from.
+ * Defaults to ''.
+ * Options: 'g', 'kg', 'lbs', 'oz'.
+ * @return float
+ */
+function wc_get_weight( $weight, $to_unit, $from_unit = '' ) {
+ $weight = (float) $weight;
+ $to_unit = strtolower( $to_unit );
+
+ if ( empty( $from_unit ) ) {
+ $from_unit = strtolower( get_option( 'woocommerce_weight_unit' ) );
+ }
+
+ // Unify all units to kg first.
+ if ( $from_unit !== $to_unit ) {
+ switch ( $from_unit ) {
+ case 'g':
+ $weight *= 0.001;
+ break;
+ case 'lbs':
+ $weight *= 0.453592;
+ break;
+ case 'oz':
+ $weight *= 0.0283495;
+ break;
+ }
+
+ // Output desired unit.
+ switch ( $to_unit ) {
+ case 'g':
+ $weight *= 1000;
+ break;
+ case 'lbs':
+ $weight *= 2.20462;
+ break;
+ case 'oz':
+ $weight *= 35.274;
+ break;
+ }
+ }
+
+ return ( $weight < 0 ) ? 0 : $weight;
+}
+
+/**
+ * Trim trailing zeros off prices.
+ *
+ * @param string|float|int $price Price.
+ * @return string
+ */
+function wc_trim_zeros( $price ) {
+ return preg_replace( '/' . preg_quote( wc_get_price_decimal_separator(), '/' ) . '0++$/', '', $price );
+}
+
+/**
+ * Round a tax amount.
+ *
+ * @param double $value Amount to round.
+ * @param int $precision DP to round. Defaults to wc_get_price_decimals.
+ * @return float
+ */
+function wc_round_tax_total( $value, $precision = null ) {
+ $precision = is_null( $precision ) ? wc_get_price_decimals() : intval( $precision );
+
+ if ( version_compare( PHP_VERSION, '5.3.0', '>=' ) ) {
+ $rounded_tax = NumberUtil::round( $value, $precision, wc_get_tax_rounding_mode() ); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctionParameters.round_modeFound
+ } elseif ( 2 === wc_get_tax_rounding_mode() ) {
+ $rounded_tax = wc_legacy_round_half_down( $value, $precision );
+ } else {
+ $rounded_tax = NumberUtil::round( $value, $precision );
+ }
+
+ return apply_filters( 'wc_round_tax_total', $rounded_tax, $value, $precision, WC_TAX_ROUNDING_MODE );
+}
+
+/**
+ * Round half down in PHP 5.2.
+ *
+ * @since 3.2.6
+ * @param float $value Value to round.
+ * @param int $precision Precision to round down to.
+ * @return float
+ */
+function wc_legacy_round_half_down( $value, $precision ) {
+ $value = wc_float_to_string( $value );
+
+ if ( false !== strstr( $value, '.' ) ) {
+ $value = explode( '.', $value );
+
+ if ( strlen( $value[1] ) > $precision && substr( $value[1], -1 ) === '5' ) {
+ $value[1] = substr( $value[1], 0, -1 ) . '4';
+ }
+
+ $value = implode( '.', $value );
+ }
+
+ return NumberUtil::round( floatval( $value ), $precision );
+}
+
+/**
+ * Make a refund total negative.
+ *
+ * @param float $amount Refunded amount.
+ *
+ * @return float
+ */
+function wc_format_refund_total( $amount ) {
+ return $amount * -1;
+}
+
+/**
+ * Format decimal numbers ready for DB storage.
+ *
+ * Sanitize, remove decimals, and optionally round + trim off zeros.
+ *
+ * This function does not remove thousands - this should be done before passing a value to the function.
+ *
+ * @param float|string $number Expects either a float or a string with a decimal separator only (no thousands).
+ * @param mixed $dp number Number of decimal points to use, blank to use woocommerce_price_num_decimals, or false to avoid all rounding.
+ * @param bool $trim_zeros From end of string.
+ * @return string
+ */
+function wc_format_decimal( $number, $dp = false, $trim_zeros = false ) {
+ $locale = localeconv();
+ $decimals = array( wc_get_price_decimal_separator(), $locale['decimal_point'], $locale['mon_decimal_point'] );
+
+ // Remove locale from string.
+ if ( ! is_float( $number ) ) {
+ $number = str_replace( $decimals, '.', $number );
+
+ // Convert multiple dots to just one.
+ $number = preg_replace( '/\.(?![^.]+$)|[^0-9.-]/', '', wc_clean( $number ) );
+ }
+
+ if ( false !== $dp ) {
+ $dp = intval( '' === $dp ? wc_get_price_decimals() : $dp );
+ $number = number_format( floatval( $number ), $dp, '.', '' );
+ } elseif ( is_float( $number ) ) {
+ // DP is false - don't use number format, just return a string using whatever is given. Remove scientific notation using sprintf.
+ $number = str_replace( $decimals, '.', sprintf( '%.' . wc_get_rounding_precision() . 'f', $number ) );
+ // We already had a float, so trailing zeros are not needed.
+ $trim_zeros = true;
+ }
+
+ if ( $trim_zeros && strstr( $number, '.' ) ) {
+ $number = rtrim( rtrim( $number, '0' ), '.' );
+ }
+
+ return $number;
+}
+
+/**
+ * Convert a float to a string without locale formatting which PHP adds when changing floats to strings.
+ *
+ * @param float $float Float value to format.
+ * @return string
+ */
+function wc_float_to_string( $float ) {
+ if ( ! is_float( $float ) ) {
+ return $float;
+ }
+
+ $locale = localeconv();
+ $string = strval( $float );
+ $string = str_replace( $locale['decimal_point'], '.', $string );
+
+ return $string;
+}
+
+/**
+ * Format a price with WC Currency Locale settings.
+ *
+ * @param string $value Price to localize.
+ * @return string
+ */
+function wc_format_localized_price( $value ) {
+ return apply_filters( 'woocommerce_format_localized_price', str_replace( '.', wc_get_price_decimal_separator(), strval( $value ) ), $value );
+}
+
+/**
+ * Format a decimal with PHP Locale settings.
+ *
+ * @param string $value Decimal to localize.
+ * @return string
+ */
+function wc_format_localized_decimal( $value ) {
+ $locale = localeconv();
+ return apply_filters( 'woocommerce_format_localized_decimal', str_replace( '.', $locale['decimal_point'], strval( $value ) ), $value );
+}
+
+/**
+ * Format a coupon code.
+ *
+ * @since 3.0.0
+ * @param string $value Coupon code to format.
+ * @return string
+ */
+function wc_format_coupon_code( $value ) {
+ return apply_filters( 'woocommerce_coupon_code', $value );
+}
+
+/**
+ * Sanitize a coupon code.
+ *
+ * Uses sanitize_post_field since coupon codes are stored as
+ * post_titles - the sanitization and escaping must match.
+ *
+ * @since 3.6.0
+ * @param string $value Coupon code to format.
+ * @return string
+ */
+function wc_sanitize_coupon_code( $value ) {
+ return wp_filter_kses( sanitize_post_field( 'post_title', $value, 0, 'db' ) );
+}
+
+/**
+ * Clean variables using sanitize_text_field. Arrays are cleaned recursively.
+ * Non-scalar values are ignored.
+ *
+ * @param string|array $var Data to sanitize.
+ * @return string|array
+ */
+function wc_clean( $var ) {
+ if ( is_array( $var ) ) {
+ return array_map( 'wc_clean', $var );
+ } else {
+ return is_scalar( $var ) ? sanitize_text_field( $var ) : $var;
+ }
+}
+
+/**
+ * Function wp_check_invalid_utf8 with recursive array support.
+ *
+ * @param string|array $var Data to sanitize.
+ * @return string|array
+ */
+function wc_check_invalid_utf8( $var ) {
+ if ( is_array( $var ) ) {
+ return array_map( 'wc_check_invalid_utf8', $var );
+ } else {
+ return wp_check_invalid_utf8( $var );
+ }
+}
+
+/**
+ * Run wc_clean over posted textarea but maintain line breaks.
+ *
+ * @since 3.0.0
+ * @param string $var Data to sanitize.
+ * @return string
+ */
+function wc_sanitize_textarea( $var ) {
+ return implode( "\n", array_map( 'wc_clean', explode( "\n", $var ) ) );
+}
+
+/**
+ * Sanitize a string destined to be a tooltip.
+ *
+ * @since 2.3.10 Tooltips are encoded with htmlspecialchars to prevent XSS. Should not be used in conjunction with esc_attr()
+ * @param string $var Data to sanitize.
+ * @return string
+ */
+function wc_sanitize_tooltip( $var ) {
+ return htmlspecialchars(
+ wp_kses(
+ html_entity_decode( $var ),
+ array(
+ 'br' => array(),
+ 'em' => array(),
+ 'strong' => array(),
+ 'small' => array(),
+ 'span' => array(),
+ 'ul' => array(),
+ 'li' => array(),
+ 'ol' => array(),
+ 'p' => array(),
+ )
+ )
+ );
+}
+
+/**
+ * Merge two arrays.
+ *
+ * @param array $a1 First array to merge.
+ * @param array $a2 Second array to merge.
+ * @return array
+ */
+function wc_array_overlay( $a1, $a2 ) {
+ foreach ( $a1 as $k => $v ) {
+ if ( ! array_key_exists( $k, $a2 ) ) {
+ continue;
+ }
+ if ( is_array( $v ) && is_array( $a2[ $k ] ) ) {
+ $a1[ $k ] = wc_array_overlay( $v, $a2[ $k ] );
+ } else {
+ $a1[ $k ] = $a2[ $k ];
+ }
+ }
+ return $a1;
+}
+
+/**
+ * Formats a stock amount by running it through a filter.
+ *
+ * @param int|float $amount Stock amount.
+ * @return int|float
+ */
+function wc_stock_amount( $amount ) {
+ return apply_filters( 'woocommerce_stock_amount', $amount );
+}
+
+/**
+ * Get the price format depending on the currency position.
+ *
+ * @return string
+ */
+function get_woocommerce_price_format() {
+ $currency_pos = get_option( 'woocommerce_currency_pos' );
+ $format = '%1$s%2$s';
+
+ switch ( $currency_pos ) {
+ case 'left':
+ $format = '%1$s%2$s';
+ break;
+ case 'right':
+ $format = '%2$s%1$s';
+ break;
+ case 'left_space':
+ $format = '%1$s %2$s';
+ break;
+ case 'right_space':
+ $format = '%2$s %1$s';
+ break;
+ }
+
+ return apply_filters( 'woocommerce_price_format', $format, $currency_pos );
+}
+
+/**
+ * Return the thousand separator for prices.
+ *
+ * @since 2.3
+ * @return string
+ */
+function wc_get_price_thousand_separator() {
+ return stripslashes( apply_filters( 'wc_get_price_thousand_separator', get_option( 'woocommerce_price_thousand_sep' ) ) );
+}
+
+/**
+ * Return the decimal separator for prices.
+ *
+ * @since 2.3
+ * @return string
+ */
+function wc_get_price_decimal_separator() {
+ $separator = apply_filters( 'wc_get_price_decimal_separator', get_option( 'woocommerce_price_decimal_sep' ) );
+ return $separator ? stripslashes( $separator ) : '.';
+}
+
+/**
+ * Return the number of decimals after the decimal point.
+ *
+ * @since 2.3
+ * @return int
+ */
+function wc_get_price_decimals() {
+ return absint( apply_filters( 'wc_get_price_decimals', get_option( 'woocommerce_price_num_decimals', 2 ) ) );
+}
+
+/**
+ * Format the price with a currency symbol.
+ *
+ * @param float $price Raw price.
+ * @param array $args Arguments to format a price {
+ * Array of arguments.
+ * Defaults to empty array.
+ *
+ * @type bool $ex_tax_label Adds exclude tax label.
+ * Defaults to false.
+ * @type string $currency Currency code.
+ * Defaults to empty string (Use the result from get_woocommerce_currency()).
+ * @type string $decimal_separator Decimal separator.
+ * Defaults the result of wc_get_price_decimal_separator().
+ * @type string $thousand_separator Thousand separator.
+ * Defaults the result of wc_get_price_thousand_separator().
+ * @type string $decimals Number of decimals.
+ * Defaults the result of wc_get_price_decimals().
+ * @type string $price_format Price format depending on the currency position.
+ * Defaults the result of get_woocommerce_price_format().
+ * }
+ * @return string
+ */
+function wc_price( $price, $args = array() ) {
+ $args = apply_filters(
+ 'wc_price_args',
+ wp_parse_args(
+ $args,
+ array(
+ 'ex_tax_label' => false,
+ 'currency' => '',
+ 'decimal_separator' => wc_get_price_decimal_separator(),
+ 'thousand_separator' => wc_get_price_thousand_separator(),
+ 'decimals' => wc_get_price_decimals(),
+ 'price_format' => get_woocommerce_price_format(),
+ )
+ )
+ );
+
+ $unformatted_price = $price;
+ $negative = $price < 0;
+ $price = apply_filters( 'raw_woocommerce_price', floatval( $negative ? $price * -1 : $price ) );
+ $price = apply_filters( 'formatted_woocommerce_price', number_format( $price, $args['decimals'], $args['decimal_separator'], $args['thousand_separator'] ), $price, $args['decimals'], $args['decimal_separator'], $args['thousand_separator'] );
+
+ if ( apply_filters( 'woocommerce_price_trim_zeros', false ) && $args['decimals'] > 0 ) {
+ $price = wc_trim_zeros( $price );
+ }
+
+ $formatted_price = ( $negative ? '-' : '' ) . sprintf( $args['price_format'], '' . get_woocommerce_currency_symbol( $args['currency'] ) . '', $price );
+ $return = '' . $formatted_price . '';
+
+ if ( $args['ex_tax_label'] && wc_tax_enabled() ) {
+ $return .= ' ' . WC()->countries->ex_tax_or_vat() . '';
+ }
+
+ /**
+ * Filters the string of price markup.
+ *
+ * @param string $return Price HTML markup.
+ * @param string $price Formatted price.
+ * @param array $args Pass on the args.
+ * @param float $unformatted_price Price as float to allow plugins custom formatting. Since 3.2.0.
+ */
+ return apply_filters( 'wc_price', $return, $price, $args, $unformatted_price );
+}
+
+/**
+ * Notation to numbers.
+ *
+ * This function transforms the php.ini notation for numbers (like '2M') to an integer.
+ *
+ * @param string $size Size value.
+ * @return int
+ */
+function wc_let_to_num( $size ) {
+ $l = substr( $size, -1 );
+ $ret = (int) substr( $size, 0, -1 );
+ switch ( strtoupper( $l ) ) {
+ case 'P':
+ $ret *= 1024;
+ // No break.
+ case 'T':
+ $ret *= 1024;
+ // No break.
+ case 'G':
+ $ret *= 1024;
+ // No break.
+ case 'M':
+ $ret *= 1024;
+ // No break.
+ case 'K':
+ $ret *= 1024;
+ // No break.
+ }
+ return $ret;
+}
+
+/**
+ * WooCommerce Date Format - Allows to change date format for everything WooCommerce.
+ *
+ * @return string
+ */
+function wc_date_format() {
+ return apply_filters( 'woocommerce_date_format', get_option( 'date_format' ) );
+}
+
+/**
+ * WooCommerce Time Format - Allows to change time format for everything WooCommerce.
+ *
+ * @return string
+ */
+function wc_time_format() {
+ return apply_filters( 'woocommerce_time_format', get_option( 'time_format' ) );
+}
+
+/**
+ * Convert mysql datetime to PHP timestamp, forcing UTC. Wrapper for strtotime.
+ *
+ * Based on wcs_strtotime_dark_knight() from WC Subscriptions by Prospress.
+ *
+ * @since 3.0.0
+ * @param string $time_string Time string.
+ * @param int|null $from_timestamp Timestamp to convert from.
+ * @return int
+ */
+function wc_string_to_timestamp( $time_string, $from_timestamp = null ) {
+ $original_timezone = date_default_timezone_get();
+
+ // @codingStandardsIgnoreStart
+ date_default_timezone_set( 'UTC' );
+
+ if ( null === $from_timestamp ) {
+ $next_timestamp = strtotime( $time_string );
+ } else {
+ $next_timestamp = strtotime( $time_string, $from_timestamp );
+ }
+
+ date_default_timezone_set( $original_timezone );
+ // @codingStandardsIgnoreEnd
+
+ return $next_timestamp;
+}
+
+/**
+ * Convert a date string to a WC_DateTime.
+ *
+ * @since 3.1.0
+ * @param string $time_string Time string.
+ * @return WC_DateTime
+ */
+function wc_string_to_datetime( $time_string ) {
+ // Strings are defined in local WP timezone. Convert to UTC.
+ if ( 1 === preg_match( '/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(Z|((-|\+)\d{2}:\d{2}))$/', $time_string, $date_bits ) ) {
+ $offset = ! empty( $date_bits[7] ) ? iso8601_timezone_to_offset( $date_bits[7] ) : wc_timezone_offset();
+ $timestamp = gmmktime( $date_bits[4], $date_bits[5], $date_bits[6], $date_bits[2], $date_bits[3], $date_bits[1] ) - $offset;
+ } else {
+ $timestamp = wc_string_to_timestamp( get_gmt_from_date( gmdate( 'Y-m-d H:i:s', wc_string_to_timestamp( $time_string ) ) ) );
+ }
+ $datetime = new WC_DateTime( "@{$timestamp}", new DateTimeZone( 'UTC' ) );
+
+ // Set local timezone or offset.
+ if ( get_option( 'timezone_string' ) ) {
+ $datetime->setTimezone( new DateTimeZone( wc_timezone_string() ) );
+ } else {
+ $datetime->set_utc_offset( wc_timezone_offset() );
+ }
+
+ return $datetime;
+}
+
+/**
+ * WooCommerce Timezone - helper to retrieve the timezone string for a site until.
+ * a WP core method exists (see https://core.trac.wordpress.org/ticket/24730).
+ *
+ * Adapted from https://secure.php.net/manual/en/function.timezone-name-from-abbr.php#89155.
+ *
+ * @since 2.1
+ * @return string PHP timezone string for the site
+ */
+function wc_timezone_string() {
+ // Added in WordPress 5.3 Ref https://developer.wordpress.org/reference/functions/wp_timezone_string/.
+ if ( function_exists( 'wp_timezone_string' ) ) {
+ return wp_timezone_string();
+ }
+
+ // If site timezone string exists, return it.
+ $timezone = get_option( 'timezone_string' );
+ if ( $timezone ) {
+ return $timezone;
+ }
+
+ // Get UTC offset, if it isn't set then return UTC.
+ $utc_offset = floatval( get_option( 'gmt_offset', 0 ) );
+ if ( ! is_numeric( $utc_offset ) || 0.0 === $utc_offset ) {
+ return 'UTC';
+ }
+
+ // Adjust UTC offset from hours to seconds.
+ $utc_offset = (int) ( $utc_offset * 3600 );
+
+ // Attempt to guess the timezone string from the UTC offset.
+ $timezone = timezone_name_from_abbr( '', $utc_offset );
+ if ( $timezone ) {
+ return $timezone;
+ }
+
+ // Last try, guess timezone string manually.
+ foreach ( timezone_abbreviations_list() as $abbr ) {
+ foreach ( $abbr as $city ) {
+ // WordPress restrict the use of date(), since it's affected by timezone settings, but in this case is just what we need to guess the correct timezone.
+ if ( (bool) date( 'I' ) === (bool) $city['dst'] && $city['timezone_id'] && intval( $city['offset'] ) === $utc_offset ) { // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
+ return $city['timezone_id'];
+ }
+ }
+ }
+
+ // Fallback to UTC.
+ return 'UTC';
+}
+
+/**
+ * Get timezone offset in seconds.
+ *
+ * @since 3.0.0
+ * @return float
+ */
+function wc_timezone_offset() {
+ $timezone = get_option( 'timezone_string' );
+
+ if ( $timezone ) {
+ $timezone_object = new DateTimeZone( $timezone );
+ return $timezone_object->getOffset( new DateTime( 'now' ) );
+ } else {
+ return floatval( get_option( 'gmt_offset', 0 ) ) * HOUR_IN_SECONDS;
+ }
+}
+
+/**
+ * Callback which can flatten post meta (gets the first value if it's an array).
+ *
+ * @since 3.0.0
+ * @param array $value Value to flatten.
+ * @return mixed
+ */
+function wc_flatten_meta_callback( $value ) {
+ return is_array( $value ) ? current( $value ) : $value;
+}
+
+if ( ! function_exists( 'wc_rgb_from_hex' ) ) {
+
+ /**
+ * Convert RGB to HEX.
+ *
+ * @param mixed $color Color.
+ *
+ * @return array
+ */
+ function wc_rgb_from_hex( $color ) {
+ $color = str_replace( '#', '', $color );
+ // Convert shorthand colors to full format, e.g. "FFF" -> "FFFFFF".
+ $color = preg_replace( '~^(.)(.)(.)$~', '$1$1$2$2$3$3', $color );
+
+ $rgb = array();
+ $rgb['R'] = hexdec( $color[0] . $color[1] );
+ $rgb['G'] = hexdec( $color[2] . $color[3] );
+ $rgb['B'] = hexdec( $color[4] . $color[5] );
+
+ return $rgb;
+ }
+}
+
+if ( ! function_exists( 'wc_hex_darker' ) ) {
+
+ /**
+ * Make HEX color darker.
+ *
+ * @param mixed $color Color.
+ * @param int $factor Darker factor.
+ * Defaults to 30.
+ * @return string
+ */
+ function wc_hex_darker( $color, $factor = 30 ) {
+ $base = wc_rgb_from_hex( $color );
+ $color = '#';
+
+ foreach ( $base as $k => $v ) {
+ $amount = $v / 100;
+ $amount = NumberUtil::round( $amount * $factor );
+ $new_decimal = $v - $amount;
+
+ $new_hex_component = dechex( $new_decimal );
+ if ( strlen( $new_hex_component ) < 2 ) {
+ $new_hex_component = '0' . $new_hex_component;
+ }
+ $color .= $new_hex_component;
+ }
+
+ return $color;
+ }
+}
+
+if ( ! function_exists( 'wc_hex_lighter' ) ) {
+
+ /**
+ * Make HEX color lighter.
+ *
+ * @param mixed $color Color.
+ * @param int $factor Lighter factor.
+ * Defaults to 30.
+ * @return string
+ */
+ function wc_hex_lighter( $color, $factor = 30 ) {
+ $base = wc_rgb_from_hex( $color );
+ $color = '#';
+
+ foreach ( $base as $k => $v ) {
+ $amount = 255 - $v;
+ $amount = $amount / 100;
+ $amount = NumberUtil::round( $amount * $factor );
+ $new_decimal = $v + $amount;
+
+ $new_hex_component = dechex( $new_decimal );
+ if ( strlen( $new_hex_component ) < 2 ) {
+ $new_hex_component = '0' . $new_hex_component;
+ }
+ $color .= $new_hex_component;
+ }
+
+ return $color;
+ }
+}
+
+if ( ! function_exists( 'wc_hex_is_light' ) ) {
+
+ /**
+ * Determine whether a hex color is light.
+ *
+ * @param mixed $color Color.
+ * @return bool True if a light color.
+ */
+ function wc_hex_is_light( $color ) {
+ $hex = str_replace( '#', '', $color );
+
+ $c_r = hexdec( substr( $hex, 0, 2 ) );
+ $c_g = hexdec( substr( $hex, 2, 2 ) );
+ $c_b = hexdec( substr( $hex, 4, 2 ) );
+
+ $brightness = ( ( $c_r * 299 ) + ( $c_g * 587 ) + ( $c_b * 114 ) ) / 1000;
+
+ return $brightness > 155;
+ }
+}
+
+if ( ! function_exists( 'wc_light_or_dark' ) ) {
+
+ /**
+ * Detect if we should use a light or dark color on a background color.
+ *
+ * @param mixed $color Color.
+ * @param string $dark Darkest reference.
+ * Defaults to '#000000'.
+ * @param string $light Lightest reference.
+ * Defaults to '#FFFFFF'.
+ * @return string
+ */
+ function wc_light_or_dark( $color, $dark = '#000000', $light = '#FFFFFF' ) {
+ return wc_hex_is_light( $color ) ? $dark : $light;
+ }
+}
+
+if ( ! function_exists( 'wc_format_hex' ) ) {
+
+ /**
+ * Format string as hex.
+ *
+ * @param string $hex HEX color.
+ * @return string|null
+ */
+ function wc_format_hex( $hex ) {
+ $hex = trim( str_replace( '#', '', $hex ) );
+
+ if ( strlen( $hex ) === 3 ) {
+ $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
+ }
+
+ return $hex ? '#' . $hex : null;
+ }
+}
+
+/**
+ * Format the postcode according to the country and length of the postcode.
+ *
+ * @param string $postcode Unformatted postcode.
+ * @param string $country Base country.
+ * @return string
+ */
+function wc_format_postcode( $postcode, $country ) {
+ $postcode = wc_normalize_postcode( $postcode );
+
+ switch ( $country ) {
+ case 'CA':
+ case 'GB':
+ $postcode = substr_replace( $postcode, ' ', -3, 0 );
+ break;
+ case 'IE':
+ $postcode = substr_replace( $postcode, ' ', 3, 0 );
+ break;
+ case 'BR':
+ case 'PL':
+ $postcode = substr_replace( $postcode, '-', -3, 0 );
+ break;
+ case 'JP':
+ $postcode = substr_replace( $postcode, '-', 3, 0 );
+ break;
+ case 'PT':
+ $postcode = substr_replace( $postcode, '-', 4, 0 );
+ break;
+ case 'PR':
+ case 'US':
+ $postcode = rtrim( substr_replace( $postcode, '-', 5, 0 ), '-' );
+ break;
+ case 'NL':
+ $postcode = substr_replace( $postcode, ' ', 4, 0 );
+ break;
+ }
+
+ return apply_filters( 'woocommerce_format_postcode', trim( $postcode ), $country );
+}
+
+/**
+ * Normalize postcodes.
+ *
+ * Remove spaces and convert characters to uppercase.
+ *
+ * @since 2.6.0
+ * @param string $postcode Postcode.
+ * @return string
+ */
+function wc_normalize_postcode( $postcode ) {
+ return preg_replace( '/[\s\-]/', '', trim( wc_strtoupper( $postcode ) ) );
+}
+
+/**
+ * Format phone numbers.
+ *
+ * @param string $phone Phone number.
+ * @return string
+ */
+function wc_format_phone_number( $phone ) {
+ if ( ! WC_Validation::is_phone( $phone ) ) {
+ return '';
+ }
+ return preg_replace( '/[^0-9\+\-\(\)\s]/', '-', preg_replace( '/[\x00-\x1F\x7F-\xFF]/', '', $phone ) );
+}
+
+/**
+ * Sanitize phone number.
+ * Allows only numbers and "+" (plus sign).
+ *
+ * @since 3.6.0
+ * @param string $phone Phone number.
+ * @return string
+ */
+function wc_sanitize_phone_number( $phone ) {
+ return preg_replace( '/[^\d+]/', '', $phone );
+}
+
+/**
+ * Wrapper for mb_strtoupper which see's if supported first.
+ *
+ * @since 3.1.0
+ * @param string $string String to format.
+ * @return string
+ */
+function wc_strtoupper( $string ) {
+ return function_exists( 'mb_strtoupper' ) ? mb_strtoupper( $string ) : strtoupper( $string );
+}
+
+/**
+ * Make a string lowercase.
+ * Try to use mb_strtolower() when available.
+ *
+ * @since 2.3
+ * @param string $string String to format.
+ * @return string
+ */
+function wc_strtolower( $string ) {
+ return function_exists( 'mb_strtolower' ) ? mb_strtolower( $string ) : strtolower( $string );
+}
+
+/**
+ * Trim a string and append a suffix.
+ *
+ * @param string $string String to trim.
+ * @param integer $chars Amount of characters.
+ * Defaults to 200.
+ * @param string $suffix Suffix.
+ * Defaults to '...'.
+ * @return string
+ */
+function wc_trim_string( $string, $chars = 200, $suffix = '...' ) {
+ if ( strlen( $string ) > $chars ) {
+ if ( function_exists( 'mb_substr' ) ) {
+ $string = mb_substr( $string, 0, ( $chars - mb_strlen( $suffix ) ) ) . $suffix;
+ } else {
+ $string = substr( $string, 0, ( $chars - strlen( $suffix ) ) ) . $suffix;
+ }
+ }
+ return $string;
+}
+
+/**
+ * Format content to display shortcodes.
+ *
+ * @since 2.3.0
+ * @param string $raw_string Raw string.
+ * @return string
+ */
+function wc_format_content( $raw_string ) {
+ return apply_filters( 'woocommerce_format_content', apply_filters( 'woocommerce_short_description', $raw_string ), $raw_string );
+}
+
+/**
+ * Format product short description.
+ * Adds support for Jetpack Markdown.
+ *
+ * @codeCoverageIgnore
+ * @since 2.4.0
+ * @param string $content Product short description.
+ * @return string
+ */
+function wc_format_product_short_description( $content ) {
+ // Add support for Jetpack Markdown.
+ if ( class_exists( 'WPCom_Markdown' ) ) {
+ $markdown = WPCom_Markdown::get_instance();
+
+ return wpautop(
+ $markdown->transform(
+ $content,
+ array(
+ 'unslash' => false,
+ )
+ )
+ );
+ }
+
+ return $content;
+}
+
+/**
+ * Formats curency symbols when saved in settings.
+ *
+ * @codeCoverageIgnore
+ * @param string $value Option value.
+ * @param array $option Option name.
+ * @param string $raw_value Raw value.
+ * @return string
+ */
+function wc_format_option_price_separators( $value, $option, $raw_value ) {
+ return wp_kses_post( $raw_value );
+}
+add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_price_decimal_sep', 'wc_format_option_price_separators', 10, 3 );
+add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_price_thousand_sep', 'wc_format_option_price_separators', 10, 3 );
+
+/**
+ * Formats decimals when saved in settings.
+ *
+ * @codeCoverageIgnore
+ * @param string $value Option value.
+ * @param array $option Option name.
+ * @param string $raw_value Raw value.
+ * @return string
+ */
+function wc_format_option_price_num_decimals( $value, $option, $raw_value ) {
+ return is_null( $raw_value ) ? 2 : absint( $raw_value );
+}
+add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_price_num_decimals', 'wc_format_option_price_num_decimals', 10, 3 );
+
+/**
+ * Formats hold stock option and sets cron event up.
+ *
+ * @codeCoverageIgnore
+ * @param string $value Option value.
+ * @param array $option Option name.
+ * @param string $raw_value Raw value.
+ * @return string
+ */
+function wc_format_option_hold_stock_minutes( $value, $option, $raw_value ) {
+ $value = ! empty( $raw_value ) ? absint( $raw_value ) : ''; // Allow > 0 or set to ''.
+
+ wp_clear_scheduled_hook( 'woocommerce_cancel_unpaid_orders' );
+
+ if ( '' !== $value ) {
+ wp_schedule_single_event( time() + ( absint( $value ) * 60 ), 'woocommerce_cancel_unpaid_orders' );
+ }
+
+ return $value;
+}
+add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_hold_stock_minutes', 'wc_format_option_hold_stock_minutes', 10, 3 );
+
+/**
+ * Sanitize terms from an attribute text based.
+ *
+ * @since 2.4.5
+ * @param string $term Term value.
+ * @return string
+ */
+function wc_sanitize_term_text_based( $term ) {
+ return trim( wp_strip_all_tags( wp_unslash( $term ) ) );
+}
+
+if ( ! function_exists( 'wc_make_numeric_postcode' ) ) {
+ /**
+ * Make numeric postcode.
+ *
+ * Converts letters to numbers so we can do a simple range check on postcodes.
+ * E.g. PE30 becomes 16050300 (P = 16, E = 05, 3 = 03, 0 = 00)
+ *
+ * @since 2.6.0
+ * @param string $postcode Regular postcode.
+ * @return string
+ */
+ function wc_make_numeric_postcode( $postcode ) {
+ $postcode = str_replace( array( ' ', '-' ), '', $postcode );
+ $postcode_length = strlen( $postcode );
+ $letters_to_numbers = array_merge( array( 0 ), range( 'A', 'Z' ) );
+ $letters_to_numbers = array_flip( $letters_to_numbers );
+ $numeric_postcode = '';
+
+ for ( $i = 0; $i < $postcode_length; $i ++ ) {
+ if ( is_numeric( $postcode[ $i ] ) ) {
+ $numeric_postcode .= str_pad( $postcode[ $i ], 2, '0', STR_PAD_LEFT );
+ } elseif ( isset( $letters_to_numbers[ $postcode[ $i ] ] ) ) {
+ $numeric_postcode .= str_pad( $letters_to_numbers[ $postcode[ $i ] ], 2, '0', STR_PAD_LEFT );
+ } else {
+ $numeric_postcode .= '00';
+ }
+ }
+
+ return $numeric_postcode;
+ }
+}
+
+/**
+ * Format the stock amount ready for display based on settings.
+ *
+ * @since 3.0.0
+ * @param WC_Product $product Product object for which the stock you need to format.
+ * @return string
+ */
+function wc_format_stock_for_display( $product ) {
+ $display = __( 'In stock', 'woocommerce' );
+ $stock_amount = $product->get_stock_quantity();
+
+ switch ( get_option( 'woocommerce_stock_format' ) ) {
+ case 'low_amount':
+ if ( $stock_amount <= get_option( 'woocommerce_notify_low_stock_amount' ) ) {
+ /* translators: %s: stock amount */
+ $display = sprintf( __( 'Only %s left in stock', 'woocommerce' ), wc_format_stock_quantity_for_display( $stock_amount, $product ) );
+ }
+ break;
+ case '':
+ /* translators: %s: stock amount */
+ $display = sprintf( __( '%s in stock', 'woocommerce' ), wc_format_stock_quantity_for_display( $stock_amount, $product ) );
+ break;
+ }
+
+ if ( $product->backorders_allowed() && $product->backorders_require_notification() ) {
+ $display .= ' ' . __( '(can be backordered)', 'woocommerce' );
+ }
+
+ return $display;
+}
+
+/**
+ * Format the stock quantity ready for display.
+ *
+ * @since 3.0.0
+ * @param int $stock_quantity Stock quantity.
+ * @param WC_Product $product Product instance so that we can pass through the filters.
+ * @return string
+ */
+function wc_format_stock_quantity_for_display( $stock_quantity, $product ) {
+ return apply_filters( 'woocommerce_format_stock_quantity', $stock_quantity, $product );
+}
+
+/**
+ * Format a sale price for display.
+ *
+ * @since 3.0.0
+ * @param string $regular_price Regular price.
+ * @param string $sale_price Sale price.
+ * @return string
+ */
+function wc_format_sale_price( $regular_price, $sale_price ) {
+ $price = '' . ( is_numeric( $regular_price ) ? wc_price( $regular_price ) : $regular_price ) . ' ' . ( is_numeric( $sale_price ) ? wc_price( $sale_price ) : $sale_price ) . '';
+ return apply_filters( 'woocommerce_format_sale_price', $price, $regular_price, $sale_price );
+}
+
+/**
+ * Format a price range for display.
+ *
+ * @param string $from Price from.
+ * @param string $to Price to.
+ * @return string
+ */
+function wc_format_price_range( $from, $to ) {
+ /* translators: 1: price from 2: price to */
+ $price = sprintf( _x( '%1$s – %2$s', 'Price range: from-to', 'woocommerce' ), is_numeric( $from ) ? wc_price( $from ) : $from, is_numeric( $to ) ? wc_price( $to ) : $to );
+ return apply_filters( 'woocommerce_format_price_range', $price, $from, $to );
+}
+
+/**
+ * Format a weight for display.
+ *
+ * @since 3.0.0
+ * @param float $weight Weight.
+ * @return string
+ */
+function wc_format_weight( $weight ) {
+ $weight_string = wc_format_localized_decimal( $weight );
+
+ if ( ! empty( $weight_string ) ) {
+ $weight_string .= ' ' . get_option( 'woocommerce_weight_unit' );
+ } else {
+ $weight_string = __( 'N/A', 'woocommerce' );
+ }
+
+ return apply_filters( 'woocommerce_format_weight', $weight_string, $weight );
+}
+
+/**
+ * Format dimensions for display.
+ *
+ * @since 3.0.0
+ * @param array $dimensions Array of dimensions.
+ * @return string
+ */
+function wc_format_dimensions( $dimensions ) {
+ $dimension_string = implode( ' × ', array_filter( array_map( 'wc_format_localized_decimal', $dimensions ) ) );
+
+ if ( ! empty( $dimension_string ) ) {
+ $dimension_string .= ' ' . get_option( 'woocommerce_dimension_unit' );
+ } else {
+ $dimension_string = __( 'N/A', 'woocommerce' );
+ }
+
+ return apply_filters( 'woocommerce_format_dimensions', $dimension_string, $dimensions );
+}
+
+/**
+ * Format a date for output.
+ *
+ * @since 3.0.0
+ * @param WC_DateTime $date Instance of WC_DateTime.
+ * @param string $format Data format.
+ * Defaults to the wc_date_format function if not set.
+ * @return string
+ */
+function wc_format_datetime( $date, $format = '' ) {
+ if ( ! $format ) {
+ $format = wc_date_format();
+ }
+ if ( ! is_a( $date, 'WC_DateTime' ) ) {
+ return '';
+ }
+ return $date->date_i18n( $format );
+}
+
+/**
+ * Process oEmbeds.
+ *
+ * @since 3.1.0
+ * @param string $content Content.
+ * @return string
+ */
+function wc_do_oembeds( $content ) {
+ global $wp_embed;
+
+ $content = $wp_embed->autoembed( $content );
+
+ return $content;
+}
+
+/**
+ * Get part of a string before :.
+ *
+ * Used for example in shipping methods ids where they take the format
+ * method_id:instance_id
+ *
+ * @since 3.2.0
+ * @param string $string String to extract.
+ * @return string
+ */
+function wc_get_string_before_colon( $string ) {
+ return trim( current( explode( ':', (string) $string ) ) );
+}
+
+/**
+ * Array merge and sum function.
+ *
+ * Source: https://gist.github.com/Nickology/f700e319cbafab5eaedc
+ *
+ * @since 3.2.0
+ * @return array
+ */
+function wc_array_merge_recursive_numeric() {
+ $arrays = func_get_args();
+
+ // If there's only one array, it's already merged.
+ if ( 1 === count( $arrays ) ) {
+ return $arrays[0];
+ }
+
+ // Remove any items in $arrays that are NOT arrays.
+ foreach ( $arrays as $key => $array ) {
+ if ( ! is_array( $array ) ) {
+ unset( $arrays[ $key ] );
+ }
+ }
+
+ // We start by setting the first array as our final array.
+ // We will merge all other arrays with this one.
+ $final = array_shift( $arrays );
+
+ foreach ( $arrays as $b ) {
+ foreach ( $final as $key => $value ) {
+ // If $key does not exist in $b, then it is unique and can be safely merged.
+ if ( ! isset( $b[ $key ] ) ) {
+ $final[ $key ] = $value;
+ } else {
+ // If $key is present in $b, then we need to merge and sum numeric values in both.
+ if ( is_numeric( $value ) && is_numeric( $b[ $key ] ) ) {
+ // If both values for these keys are numeric, we sum them.
+ $final[ $key ] = $value + $b[ $key ];
+ } elseif ( is_array( $value ) && is_array( $b[ $key ] ) ) {
+ // If both values are arrays, we recursively call ourself.
+ $final[ $key ] = wc_array_merge_recursive_numeric( $value, $b[ $key ] );
+ } else {
+ // If both keys exist but differ in type, then we cannot merge them.
+ // In this scenario, we will $b's value for $key is used.
+ $final[ $key ] = $b[ $key ];
+ }
+ }
+ }
+
+ // Finally, we need to merge any keys that exist only in $b.
+ foreach ( $b as $key => $value ) {
+ if ( ! isset( $final[ $key ] ) ) {
+ $final[ $key ] = $value;
+ }
+ }
+ }
+
+ return $final;
+}
+
+/**
+ * Implode and escape HTML attributes for output.
+ *
+ * @since 3.3.0
+ * @param array $raw_attributes Attribute name value pairs.
+ * @return string
+ */
+function wc_implode_html_attributes( $raw_attributes ) {
+ $attributes = array();
+ foreach ( $raw_attributes as $name => $value ) {
+ $attributes[] = esc_attr( $name ) . '="' . esc_attr( $value ) . '"';
+ }
+ return implode( ' ', $attributes );
+}
+
+/**
+ * Escape JSON for use on HTML or attribute text nodes.
+ *
+ * @since 3.5.5
+ * @param string $json JSON to escape.
+ * @param bool $html True if escaping for HTML text node, false for attributes. Determines how quotes are handled.
+ * @return string Escaped JSON.
+ */
+function wc_esc_json( $json, $html = false ) {
+ return _wp_specialchars(
+ $json,
+ $html ? ENT_NOQUOTES : ENT_QUOTES, // Escape quotes in attribute nodes only.
+ 'UTF-8', // json_encode() outputs UTF-8 (really just ASCII), not the blog's charset.
+ true // Double escape entities: `&` -> `&`.
+ );
+}
+
+/**
+ * Parse a relative date option from the settings API into a standard format.
+ *
+ * @since 3.4.0
+ * @param mixed $raw_value Value stored in DB.
+ * @return array Nicely formatted array with number and unit values.
+ */
+function wc_parse_relative_date_option( $raw_value ) {
+ $periods = array(
+ 'days' => __( 'Day(s)', 'woocommerce' ),
+ 'weeks' => __( 'Week(s)', 'woocommerce' ),
+ 'months' => __( 'Month(s)', 'woocommerce' ),
+ 'years' => __( 'Year(s)', 'woocommerce' ),
+ );
+
+ $value = wp_parse_args(
+ (array) $raw_value,
+ array(
+ 'number' => '',
+ 'unit' => 'days',
+ )
+ );
+
+ $value['number'] = ! empty( $value['number'] ) ? absint( $value['number'] ) : '';
+
+ if ( ! in_array( $value['unit'], array_keys( $periods ), true ) ) {
+ $value['unit'] = 'days';
+ }
+
+ return $value;
+}
+
+/**
+ * Format the endpoint slug, strip out anything not allowed in a url.
+ *
+ * @since 3.5.0
+ * @param string $raw_value The raw value.
+ * @return string
+ */
+function wc_sanitize_endpoint_slug( $raw_value ) {
+ return sanitize_title( $raw_value );
+}
+add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_checkout_pay_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 );
+add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_checkout_order_received_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 );
+add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_myaccount_add_payment_method_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 );
+add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_myaccount_delete_payment_method_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 );
+add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_myaccount_set_default_payment_method_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 );
+add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_myaccount_orders_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 );
+add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_myaccount_view_order_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 );
+add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_myaccount_downloads_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 );
+add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_myaccount_edit_account_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 );
+add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_myaccount_edit_address_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 );
+add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_myaccount_payment_methods_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 );
+add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_myaccount_lost_password_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 );
+add_filter( 'woocommerce_admin_settings_sanitize_option_woocommerce_logout_endpoint', 'wc_sanitize_endpoint_slug', 10, 1 );
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-notice-functions.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-notice-functions.php
new file mode 100644
index 0000000..e119e58
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-notice-functions.php
@@ -0,0 +1,294 @@
+session->get( 'wc_notices', array() );
+
+ if ( isset( $all_notices[ $notice_type ] ) ) {
+
+ $notice_count = count( $all_notices[ $notice_type ] );
+
+ } elseif ( empty( $notice_type ) ) {
+
+ foreach ( $all_notices as $notices ) {
+ $notice_count += count( $notices );
+ }
+ }
+
+ return $notice_count;
+}
+
+/**
+ * Check if a notice has already been added.
+ *
+ * @since 2.1
+ * @param string $message The text to display in the notice.
+ * @param string $notice_type Optional. The name of the notice type - either error, success or notice.
+ * @return bool
+ */
+function wc_has_notice( $message, $notice_type = 'success' ) {
+ if ( ! did_action( 'woocommerce_init' ) ) {
+ wc_doing_it_wrong( __FUNCTION__, __( 'This function should not be called before woocommerce_init.', 'woocommerce' ), '2.3' );
+ return false;
+ }
+
+ $notices = WC()->session->get( 'wc_notices', array() );
+ $notices = isset( $notices[ $notice_type ] ) ? $notices[ $notice_type ] : array();
+ return array_search( $message, wp_list_pluck( $notices, 'notice' ), true ) !== false;
+}
+
+/**
+ * Add and store a notice.
+ *
+ * @since 2.1
+ * @version 3.9.0
+ * @param string $message The text to display in the notice.
+ * @param string $notice_type Optional. The name of the notice type - either error, success or notice.
+ * @param array $data Optional notice data.
+ */
+function wc_add_notice( $message, $notice_type = 'success', $data = array() ) {
+ if ( ! did_action( 'woocommerce_init' ) ) {
+ wc_doing_it_wrong( __FUNCTION__, __( 'This function should not be called before woocommerce_init.', 'woocommerce' ), '2.3' );
+ return;
+ }
+
+ $notices = WC()->session->get( 'wc_notices', array() );
+
+ // Backward compatibility.
+ if ( 'success' === $notice_type ) {
+ $message = apply_filters( 'woocommerce_add_message', $message );
+ }
+
+ $message = apply_filters( 'woocommerce_add_' . $notice_type, $message );
+
+ if ( ! empty( $message ) ) {
+ $notices[ $notice_type ][] = array(
+ 'notice' => $message,
+ 'data' => $data,
+ );
+ }
+
+ WC()->session->set( 'wc_notices', $notices );
+}
+
+/**
+ * Set all notices at once.
+ *
+ * @since 2.6.0
+ * @param array[] $notices Array of notices.
+ */
+function wc_set_notices( $notices ) {
+ if ( ! did_action( 'woocommerce_init' ) ) {
+ wc_doing_it_wrong( __FUNCTION__, __( 'This function should not be called before woocommerce_init.', 'woocommerce' ), '2.6' );
+ return;
+ }
+
+ WC()->session->set( 'wc_notices', $notices );
+}
+
+/**
+ * Unset all notices.
+ *
+ * @since 2.1
+ */
+function wc_clear_notices() {
+ if ( ! did_action( 'woocommerce_init' ) ) {
+ wc_doing_it_wrong( __FUNCTION__, __( 'This function should not be called before woocommerce_init.', 'woocommerce' ), '2.3' );
+ return;
+ }
+ WC()->session->set( 'wc_notices', null );
+}
+
+/**
+ * Prints messages and errors which are stored in the session, then clears them.
+ *
+ * @since 2.1
+ * @param bool $return true to return rather than echo. @since 3.5.0.
+ * @return string|null
+ */
+function wc_print_notices( $return = false ) {
+ if ( ! did_action( 'woocommerce_init' ) ) {
+ wc_doing_it_wrong( __FUNCTION__, __( 'This function should not be called before woocommerce_init.', 'woocommerce' ), '2.3' );
+ return;
+ }
+
+ $all_notices = WC()->session->get( 'wc_notices', array() );
+ $notice_types = apply_filters( 'woocommerce_notice_types', array( 'error', 'success', 'notice' ) );
+
+ // Buffer output.
+ ob_start();
+
+ foreach ( $notice_types as $notice_type ) {
+ if ( wc_notice_count( $notice_type ) > 0 ) {
+ $messages = array();
+
+ foreach ( $all_notices[ $notice_type ] as $notice ) {
+ $messages[] = isset( $notice['notice'] ) ? $notice['notice'] : $notice;
+ }
+
+ wc_get_template(
+ "notices/{$notice_type}.php",
+ array(
+ 'messages' => array_filter( $messages ), // @deprecated 3.9.0
+ 'notices' => array_filter( $all_notices[ $notice_type ] ),
+ )
+ );
+ }
+ }
+
+ wc_clear_notices();
+
+ $notices = wc_kses_notice( ob_get_clean() );
+
+ if ( $return ) {
+ return $notices;
+ }
+
+ echo $notices; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+}
+
+/**
+ * Print a single notice immediately.
+ *
+ * @since 2.1
+ * @version 3.9.0
+ * @param string $message The text to display in the notice.
+ * @param string $notice_type Optional. The singular name of the notice type - either error, success or notice.
+ * @param array $data Optional notice data. @since 3.9.0.
+ */
+function wc_print_notice( $message, $notice_type = 'success', $data = array() ) {
+ if ( 'success' === $notice_type ) {
+ $message = apply_filters( 'woocommerce_add_message', $message );
+ }
+
+ $message = apply_filters( 'woocommerce_add_' . $notice_type, $message );
+
+ wc_get_template(
+ "notices/{$notice_type}.php",
+ array(
+ 'messages' => array( $message ), // @deprecated 3.9.0
+ 'notices' => array(
+ array(
+ 'notice' => $message,
+ 'data' => $data,
+ ),
+ ),
+ )
+ );
+}
+
+/**
+ * Returns all queued notices, optionally filtered by a notice type.
+ *
+ * @since 2.1
+ * @version 3.9.0
+ * @param string $notice_type Optional. The singular name of the notice type - either error, success or notice.
+ * @return array[]
+ */
+function wc_get_notices( $notice_type = '' ) {
+ if ( ! did_action( 'woocommerce_init' ) ) {
+ wc_doing_it_wrong( __FUNCTION__, __( 'This function should not be called before woocommerce_init.', 'woocommerce' ), '2.3' );
+ return;
+ }
+
+ $all_notices = WC()->session->get( 'wc_notices', array() );
+
+ if ( empty( $notice_type ) ) {
+ $notices = $all_notices;
+ } elseif ( isset( $all_notices[ $notice_type ] ) ) {
+ $notices = $all_notices[ $notice_type ];
+ } else {
+ $notices = array();
+ }
+
+ return $notices;
+}
+
+/**
+ * Add notices for WP Errors.
+ *
+ * @param WP_Error $errors Errors.
+ */
+function wc_add_wp_error_notices( $errors ) {
+ if ( is_wp_error( $errors ) && $errors->get_error_messages() ) {
+ foreach ( $errors->get_error_messages() as $error ) {
+ wc_add_notice( $error, 'error' );
+ }
+ }
+}
+
+/**
+ * Filters out the same tags as wp_kses_post, but allows tabindex for element.
+ *
+ * @since 3.5.0
+ * @param string $message Content to filter through kses.
+ * @return string
+ */
+function wc_kses_notice( $message ) {
+ $allowed_tags = array_replace_recursive(
+ wp_kses_allowed_html( 'post' ),
+ array(
+ 'a' => array(
+ 'tabindex' => true,
+ ),
+ )
+ );
+
+ /**
+ * Kses notice allowed tags.
+ *
+ * @since 3.9.0
+ * @param array[]|string $allowed_tags An array of allowed HTML elements and attributes, or a context name such as 'post'.
+ */
+ return wp_kses( $message, apply_filters( 'woocommerce_kses_notice_allowed_tags', $allowed_tags ) );
+}
+
+/**
+ * Get notice data attribute.
+ *
+ * @since 3.9.0
+ * @param array $notice Notice data.
+ * @return string
+ */
+function wc_get_notice_data_attr( $notice ) {
+ if ( empty( $notice['data'] ) ) {
+ return;
+ }
+
+ $attr = '';
+
+ foreach ( $notice['data'] as $key => $value ) {
+ $attr .= sprintf(
+ ' data-%1$s="%2$s"',
+ sanitize_title( $key ),
+ esc_attr( $value )
+ );
+ }
+
+ return $attr;
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-order-functions.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-order-functions.php
new file mode 100644
index 0000000..99f55dd
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-order-functions.php
@@ -0,0 +1,1090 @@
+ 'limit',
+ 'post_type' => 'type',
+ 'post_status' => 'status',
+ 'post_parent' => 'parent',
+ 'author' => 'customer',
+ 'email' => 'billing_email',
+ 'posts_per_page' => 'limit',
+ 'paged' => 'page',
+ );
+
+ foreach ( $map_legacy as $from => $to ) {
+ if ( isset( $args[ $from ] ) ) {
+ $args[ $to ] = $args[ $from ];
+ }
+ }
+
+ // Map legacy date args to modern date args.
+ $date_before = false;
+ $date_after = false;
+
+ if ( ! empty( $args['date_before'] ) ) {
+ $datetime = wc_string_to_datetime( $args['date_before'] );
+ $date_before = strpos( $args['date_before'], ':' ) ? $datetime->getOffsetTimestamp() : $datetime->date( 'Y-m-d' );
+ }
+ if ( ! empty( $args['date_after'] ) ) {
+ $datetime = wc_string_to_datetime( $args['date_after'] );
+ $date_after = strpos( $args['date_after'], ':' ) ? $datetime->getOffsetTimestamp() : $datetime->date( 'Y-m-d' );
+ }
+
+ if ( $date_before && $date_after ) {
+ $args['date_created'] = $date_after . '...' . $date_before;
+ } elseif ( $date_before ) {
+ $args['date_created'] = '<' . $date_before;
+ } elseif ( $date_after ) {
+ $args['date_created'] = '>' . $date_after;
+ }
+
+ $query = new WC_Order_Query( $args );
+ return $query->get_orders();
+}
+
+/**
+ * Main function for returning orders, uses the WC_Order_Factory class.
+ *
+ * @since 2.2
+ *
+ * @param mixed $the_order Post object or post ID of the order.
+ *
+ * @return bool|WC_Order|WC_Order_Refund
+ */
+function wc_get_order( $the_order = false ) {
+ if ( ! did_action( 'woocommerce_after_register_post_type' ) ) {
+ wc_doing_it_wrong( __FUNCTION__, 'wc_get_order should not be called before post types are registered (woocommerce_after_register_post_type action)', '2.5' );
+ return false;
+ }
+ return WC()->order_factory->get_order( $the_order );
+}
+
+/**
+ * Get all order statuses.
+ *
+ * @since 2.2
+ * @used-by WC_Order::set_status
+ * @return array
+ */
+function wc_get_order_statuses() {
+ $order_statuses = array(
+ 'wc-pending' => _x( 'Pending payment', 'Order status', 'woocommerce' ),
+ 'wc-processing' => _x( 'Processing', 'Order status', 'woocommerce' ),
+ 'wc-on-hold' => _x( 'On hold', 'Order status', 'woocommerce' ),
+ 'wc-completed' => _x( 'Completed', 'Order status', 'woocommerce' ),
+ 'wc-cancelled' => _x( 'Cancelled', 'Order status', 'woocommerce' ),
+ 'wc-refunded' => _x( 'Refunded', 'Order status', 'woocommerce' ),
+ 'wc-failed' => _x( 'Failed', 'Order status', 'woocommerce' ),
+ );
+ return apply_filters( 'wc_order_statuses', $order_statuses );
+}
+
+/**
+ * See if a string is an order status.
+ *
+ * @param string $maybe_status Status, including any wc- prefix.
+ * @return bool
+ */
+function wc_is_order_status( $maybe_status ) {
+ $order_statuses = wc_get_order_statuses();
+ return isset( $order_statuses[ $maybe_status ] );
+}
+
+/**
+ * Get list of statuses which are consider 'paid'.
+ *
+ * @since 3.0.0
+ * @return array
+ */
+function wc_get_is_paid_statuses() {
+ return apply_filters( 'woocommerce_order_is_paid_statuses', array( 'processing', 'completed' ) );
+}
+
+/**
+ * Get list of statuses which are consider 'pending payment'.
+ *
+ * @since 3.6.0
+ * @return array
+ */
+function wc_get_is_pending_statuses() {
+ return apply_filters( 'woocommerce_order_is_pending_statuses', array( 'pending' ) );
+}
+
+/**
+ * Get the nice name for an order status.
+ *
+ * @since 2.2
+ * @param string $status Status.
+ * @return string
+ */
+function wc_get_order_status_name( $status ) {
+ $statuses = wc_get_order_statuses();
+ $status = 'wc-' === substr( $status, 0, 3 ) ? substr( $status, 3 ) : $status;
+ $status = isset( $statuses[ 'wc-' . $status ] ) ? $statuses[ 'wc-' . $status ] : $status;
+ return $status;
+}
+
+/**
+ * Generate an order key with prefix.
+ *
+ * @since 3.5.4
+ * @param string $key Order key without a prefix. By default generates a 13 digit secret.
+ * @return string The order key.
+ */
+function wc_generate_order_key( $key = '' ) {
+ if ( '' === $key ) {
+ $key = wp_generate_password( 13, false );
+ }
+
+ return 'wc_' . apply_filters( 'woocommerce_generate_order_key', 'order_' . $key );
+}
+
+/**
+ * Finds an Order ID based on an order key.
+ *
+ * @param string $order_key An order key has generated by.
+ * @return int The ID of an order, or 0 if the order could not be found.
+ */
+function wc_get_order_id_by_order_key( $order_key ) {
+ $data_store = WC_Data_Store::load( 'order' );
+ return $data_store->get_order_id_by_order_key( $order_key );
+}
+
+/**
+ * Get all registered order types.
+ *
+ * @since 2.2
+ * @param string $for Optionally define what you are getting order types for so
+ * only relevant types are returned.
+ * e.g. for 'order-meta-boxes', 'order-count'.
+ * @return array
+ */
+function wc_get_order_types( $for = '' ) {
+ global $wc_order_types;
+
+ if ( ! is_array( $wc_order_types ) ) {
+ $wc_order_types = array();
+ }
+
+ $order_types = array();
+
+ switch ( $for ) {
+ case 'order-count':
+ foreach ( $wc_order_types as $type => $args ) {
+ if ( ! $args['exclude_from_order_count'] ) {
+ $order_types[] = $type;
+ }
+ }
+ break;
+ case 'order-meta-boxes':
+ foreach ( $wc_order_types as $type => $args ) {
+ if ( $args['add_order_meta_boxes'] ) {
+ $order_types[] = $type;
+ }
+ }
+ break;
+ case 'view-orders':
+ foreach ( $wc_order_types as $type => $args ) {
+ if ( ! $args['exclude_from_order_views'] ) {
+ $order_types[] = $type;
+ }
+ }
+ break;
+ case 'reports':
+ foreach ( $wc_order_types as $type => $args ) {
+ if ( ! $args['exclude_from_order_reports'] ) {
+ $order_types[] = $type;
+ }
+ }
+ break;
+ case 'sales-reports':
+ foreach ( $wc_order_types as $type => $args ) {
+ if ( ! $args['exclude_from_order_sales_reports'] ) {
+ $order_types[] = $type;
+ }
+ }
+ break;
+ case 'order-webhooks':
+ foreach ( $wc_order_types as $type => $args ) {
+ if ( ! $args['exclude_from_order_webhooks'] ) {
+ $order_types[] = $type;
+ }
+ }
+ break;
+ default:
+ $order_types = array_keys( $wc_order_types );
+ break;
+ }
+
+ return apply_filters( 'wc_order_types', $order_types, $for );
+}
+
+/**
+ * Get an order type by post type name.
+ *
+ * @param string $type Post type name.
+ * @return bool|array Details about the order type.
+ */
+function wc_get_order_type( $type ) {
+ global $wc_order_types;
+
+ if ( isset( $wc_order_types[ $type ] ) ) {
+ return $wc_order_types[ $type ];
+ }
+
+ return false;
+}
+
+/**
+ * Register order type. Do not use before init.
+ *
+ * Wrapper for register post type, as well as a method of telling WC which.
+ * post types are types of orders, and having them treated as such.
+ *
+ * $args are passed to register_post_type, but there are a few specific to this function:
+ * - exclude_from_orders_screen (bool) Whether or not this order type also get shown in the main.
+ * orders screen.
+ * - add_order_meta_boxes (bool) Whether or not the order type gets shop_order meta boxes.
+ * - exclude_from_order_count (bool) Whether or not this order type is excluded from counts.
+ * - exclude_from_order_views (bool) Whether or not this order type is visible by customers when.
+ * viewing orders e.g. on the my account page.
+ * - exclude_from_order_reports (bool) Whether or not to exclude this type from core reports.
+ * - exclude_from_order_sales_reports (bool) Whether or not to exclude this type from core sales reports.
+ *
+ * @since 2.2
+ * @see register_post_type for $args used in that function
+ * @param string $type Post type. (max. 20 characters, can not contain capital letters or spaces).
+ * @param array $args An array of arguments.
+ * @return bool Success or failure
+ */
+function wc_register_order_type( $type, $args = array() ) {
+ if ( post_type_exists( $type ) ) {
+ return false;
+ }
+
+ global $wc_order_types;
+
+ if ( ! is_array( $wc_order_types ) ) {
+ $wc_order_types = array();
+ }
+
+ // Register as a post type.
+ if ( is_wp_error( register_post_type( $type, $args ) ) ) {
+ return false;
+ }
+
+ // Register for WC usage.
+ $order_type_args = array(
+ 'exclude_from_orders_screen' => false,
+ 'add_order_meta_boxes' => true,
+ 'exclude_from_order_count' => false,
+ 'exclude_from_order_views' => false,
+ 'exclude_from_order_webhooks' => false,
+ 'exclude_from_order_reports' => false,
+ 'exclude_from_order_sales_reports' => false,
+ 'class_name' => 'WC_Order',
+ );
+
+ $args = array_intersect_key( $args, $order_type_args );
+ $args = wp_parse_args( $args, $order_type_args );
+ $wc_order_types[ $type ] = $args;
+
+ return true;
+}
+
+/**
+ * Return the count of processing orders.
+ *
+ * @return int
+ */
+function wc_processing_order_count() {
+ return wc_orders_count( 'processing' );
+}
+
+/**
+ * Return the orders count of a specific order status.
+ *
+ * @param string $status Status.
+ * @return int
+ */
+function wc_orders_count( $status ) {
+ $count = 0;
+ $status = 'wc-' . $status;
+ $order_statuses = array_keys( wc_get_order_statuses() );
+
+ if ( ! in_array( $status, $order_statuses, true ) ) {
+ return 0;
+ }
+
+ $cache_key = WC_Cache_Helper::get_cache_prefix( 'orders' ) . $status;
+ $cached_count = wp_cache_get( $cache_key, 'counts' );
+
+ if ( false !== $cached_count ) {
+ return $cached_count;
+ }
+
+ foreach ( wc_get_order_types( 'order-count' ) as $type ) {
+ $data_store = WC_Data_Store::load( 'shop_order' === $type ? 'order' : $type );
+ if ( $data_store ) {
+ $count += $data_store->get_order_count( $status );
+ }
+ }
+
+ wp_cache_set( $cache_key, $count, 'counts' );
+
+ return $count;
+}
+
+/**
+ * Grant downloadable product access to the file identified by $download_id.
+ *
+ * @param string $download_id File identifier.
+ * @param int|WC_Product $product Product instance or ID.
+ * @param WC_Order $order Order data.
+ * @param int $qty Quantity purchased.
+ * @return int|bool insert id or false on failure.
+ */
+function wc_downloadable_file_permission( $download_id, $product, $order, $qty = 1 ) {
+ if ( is_numeric( $product ) ) {
+ $product = wc_get_product( $product );
+ }
+ $download = new WC_Customer_Download();
+ $download->set_download_id( $download_id );
+ $download->set_product_id( $product->get_id() );
+ $download->set_user_id( $order->get_customer_id() );
+ $download->set_order_id( $order->get_id() );
+ $download->set_user_email( $order->get_billing_email() );
+ $download->set_order_key( $order->get_order_key() );
+ $download->set_downloads_remaining( 0 > $product->get_download_limit() ? '' : $product->get_download_limit() * $qty );
+ $download->set_access_granted( time() );
+ $download->set_download_count( 0 );
+
+ $expiry = $product->get_download_expiry();
+
+ if ( $expiry > 0 ) {
+ $from_date = $order->get_date_completed() ? $order->get_date_completed()->format( 'Y-m-d' ) : current_time( 'mysql', true );
+ $download->set_access_expires( strtotime( $from_date . ' + ' . $expiry . ' DAY' ) );
+ }
+
+ $download = apply_filters( 'woocommerce_downloadable_file_permission', $download, $product, $order, $qty );
+
+ return $download->save();
+}
+
+/**
+ * Order Status completed - give downloadable product access to customer.
+ *
+ * @param int $order_id Order ID.
+ * @param bool $force Force downloadable permissions.
+ */
+function wc_downloadable_product_permissions( $order_id, $force = false ) {
+ $order = wc_get_order( $order_id );
+
+ if ( ! $order || ( $order->get_data_store()->get_download_permissions_granted( $order ) && ! $force ) ) {
+ return;
+ }
+
+ if ( $order->has_status( 'processing' ) && 'no' === get_option( 'woocommerce_downloads_grant_access_after_payment' ) ) {
+ return;
+ }
+
+ if ( count( $order->get_items() ) > 0 ) {
+ foreach ( $order->get_items() as $item ) {
+ $product = $item->get_product();
+
+ if ( $product && $product->exists() && $product->is_downloadable() ) {
+ $downloads = $product->get_downloads();
+
+ foreach ( array_keys( $downloads ) as $download_id ) {
+ wc_downloadable_file_permission( $download_id, $product, $order, $item->get_quantity() );
+ }
+ }
+ }
+ }
+
+ $order->get_data_store()->set_download_permissions_granted( $order, true );
+ do_action( 'woocommerce_grant_product_download_permissions', $order_id );
+}
+add_action( 'woocommerce_order_status_completed', 'wc_downloadable_product_permissions' );
+add_action( 'woocommerce_order_status_processing', 'wc_downloadable_product_permissions' );
+
+/**
+ * Clear all transients cache for order data.
+ *
+ * @param int|WC_Order $order Order instance or ID.
+ */
+function wc_delete_shop_order_transients( $order = 0 ) {
+ if ( is_numeric( $order ) ) {
+ $order = wc_get_order( $order );
+ }
+ $reports = WC_Admin_Reports::get_reports();
+ $transients_to_clear = array(
+ 'wc_admin_report',
+ );
+
+ foreach ( $reports as $report_group ) {
+ foreach ( $report_group['reports'] as $report_key => $report ) {
+ $transients_to_clear[] = 'wc_report_' . $report_key;
+ }
+ }
+
+ foreach ( $transients_to_clear as $transient ) {
+ delete_transient( $transient );
+ }
+
+ // Clear money spent for user associated with order.
+ if ( is_a( $order, 'WC_Order' ) ) {
+ $order_id = $order->get_id();
+ delete_user_meta( $order->get_customer_id(), '_money_spent' );
+ delete_user_meta( $order->get_customer_id(), '_order_count' );
+ } else {
+ $order_id = 0;
+ }
+
+ // Increments the transient version to invalidate cache.
+ WC_Cache_Helper::get_transient_version( 'orders', true );
+
+ // Do the same for regular cache.
+ WC_Cache_Helper::invalidate_cache_group( 'orders' );
+
+ do_action( 'woocommerce_delete_shop_order_transients', $order_id );
+}
+
+/**
+ * See if we only ship to billing addresses.
+ *
+ * @return bool
+ */
+function wc_ship_to_billing_address_only() {
+ return 'billing_only' === get_option( 'woocommerce_ship_to_destination' );
+}
+
+/**
+ * Create a new order refund programmatically.
+ *
+ * Returns a new refund object on success which can then be used to add additional data.
+ *
+ * @since 2.2
+ * @throws Exception Throws exceptions when fail to create, but returns WP_Error instead.
+ * @param array $args New refund arguments.
+ * @return WC_Order_Refund|WP_Error
+ */
+function wc_create_refund( $args = array() ) {
+ $default_args = array(
+ 'amount' => 0,
+ 'reason' => null,
+ 'order_id' => 0,
+ 'refund_id' => 0,
+ 'line_items' => array(),
+ 'refund_payment' => false,
+ 'restock_items' => false,
+ );
+
+ try {
+ $args = wp_parse_args( $args, $default_args );
+ $order = wc_get_order( $args['order_id'] );
+
+ if ( ! $order ) {
+ throw new Exception( __( 'Invalid order ID.', 'woocommerce' ) );
+ }
+
+ $remaining_refund_amount = $order->get_remaining_refund_amount();
+ $remaining_refund_items = $order->get_remaining_refund_items();
+ $refund_item_count = 0;
+ $refund = new WC_Order_Refund( $args['refund_id'] );
+
+ if ( 0 > $args['amount'] || $args['amount'] > $remaining_refund_amount ) {
+ throw new Exception( __( 'Invalid refund amount.', 'woocommerce' ) );
+ }
+
+ $refund->set_currency( $order->get_currency() );
+ $refund->set_amount( $args['amount'] );
+ $refund->set_parent_id( absint( $args['order_id'] ) );
+ $refund->set_refunded_by( get_current_user_id() ? get_current_user_id() : 1 );
+ $refund->set_prices_include_tax( $order->get_prices_include_tax() );
+
+ if ( ! is_null( $args['reason'] ) ) {
+ $refund->set_reason( $args['reason'] );
+ }
+
+ // Negative line items.
+ if ( count( $args['line_items'] ) > 0 ) {
+ $items = $order->get_items( array( 'line_item', 'fee', 'shipping' ) );
+
+ foreach ( $items as $item_id => $item ) {
+ if ( ! isset( $args['line_items'][ $item_id ] ) ) {
+ continue;
+ }
+
+ $qty = isset( $args['line_items'][ $item_id ]['qty'] ) ? $args['line_items'][ $item_id ]['qty'] : 0;
+ $refund_total = $args['line_items'][ $item_id ]['refund_total'];
+ $refund_tax = isset( $args['line_items'][ $item_id ]['refund_tax'] ) ? array_filter( (array) $args['line_items'][ $item_id ]['refund_tax'] ) : array();
+
+ if ( empty( $qty ) && empty( $refund_total ) && empty( $args['line_items'][ $item_id ]['refund_tax'] ) ) {
+ continue;
+ }
+
+ $class = get_class( $item );
+ $refunded_item = new $class( $item );
+ $refunded_item->set_id( 0 );
+ $refunded_item->add_meta_data( '_refunded_item_id', $item_id, true );
+ $refunded_item->set_total( wc_format_refund_total( $refund_total ) );
+ $refunded_item->set_taxes(
+ array(
+ 'total' => array_map( 'wc_format_refund_total', $refund_tax ),
+ 'subtotal' => array_map( 'wc_format_refund_total', $refund_tax ),
+ )
+ );
+
+ if ( is_callable( array( $refunded_item, 'set_subtotal' ) ) ) {
+ $refunded_item->set_subtotal( wc_format_refund_total( $refund_total ) );
+ }
+
+ if ( is_callable( array( $refunded_item, 'set_quantity' ) ) ) {
+ $refunded_item->set_quantity( $qty * -1 );
+ }
+
+ $refund->add_item( $refunded_item );
+ $refund_item_count += $qty;
+ }
+ }
+
+ $refund->update_taxes();
+ $refund->calculate_totals( false );
+ $refund->set_total( $args['amount'] * -1 );
+
+ // this should remain after update_taxes(), as this will save the order, and write the current date to the db
+ // so we must wait until the order is persisted to set the date.
+ if ( isset( $args['date_created'] ) ) {
+ $refund->set_date_created( $args['date_created'] );
+ }
+
+ /**
+ * Action hook to adjust refund before save.
+ *
+ * @since 3.0.0
+ */
+ do_action( 'woocommerce_create_refund', $refund, $args );
+
+ if ( $refund->save() ) {
+ if ( $args['refund_payment'] ) {
+ $result = wc_refund_payment( $order, $refund->get_amount(), $refund->get_reason() );
+
+ if ( is_wp_error( $result ) ) {
+ $refund->delete();
+ return $result;
+ }
+
+ $refund->set_refunded_payment( true );
+ $refund->save();
+ }
+
+ if ( $args['restock_items'] ) {
+ wc_restock_refunded_items( $order, $args['line_items'] );
+ }
+
+ // Trigger notification emails.
+ if ( ( $remaining_refund_amount - $args['amount'] ) > 0 || ( $order->has_free_item() && ( $remaining_refund_items - $refund_item_count ) > 0 ) ) {
+ do_action( 'woocommerce_order_partially_refunded', $order->get_id(), $refund->get_id() );
+ } else {
+ do_action( 'woocommerce_order_fully_refunded', $order->get_id(), $refund->get_id() );
+
+ $parent_status = apply_filters( 'woocommerce_order_fully_refunded_status', 'refunded', $order->get_id(), $refund->get_id() );
+
+ if ( $parent_status ) {
+ $order->update_status( $parent_status );
+ }
+ }
+ }
+
+ do_action( 'woocommerce_refund_created', $refund->get_id(), $args );
+ do_action( 'woocommerce_order_refunded', $order->get_id(), $refund->get_id() );
+
+ } catch ( Exception $e ) {
+ if ( isset( $refund ) && is_a( $refund, 'WC_Order_Refund' ) ) {
+ wp_delete_post( $refund->get_id(), true );
+ }
+ return new WP_Error( 'error', $e->getMessage() );
+ }
+
+ return $refund;
+}
+
+/**
+ * Try to refund the payment for an order via the gateway.
+ *
+ * @since 3.0.0
+ * @throws Exception Throws exceptions when fail to refund, but returns WP_Error instead.
+ * @param WC_Order $order Order instance.
+ * @param string $amount Amount to refund.
+ * @param string $reason Refund reason.
+ * @return bool|WP_Error
+ */
+function wc_refund_payment( $order, $amount, $reason = '' ) {
+ try {
+ if ( ! is_a( $order, 'WC_Order' ) ) {
+ throw new Exception( __( 'Invalid order.', 'woocommerce' ) );
+ }
+
+ $gateway_controller = WC_Payment_Gateways::instance();
+ $all_gateways = $gateway_controller->payment_gateways();
+ $payment_method = $order->get_payment_method();
+ $gateway = isset( $all_gateways[ $payment_method ] ) ? $all_gateways[ $payment_method ] : false;
+
+ if ( ! $gateway ) {
+ throw new Exception( __( 'The payment gateway for this order does not exist.', 'woocommerce' ) );
+ }
+
+ if ( ! $gateway->supports( 'refunds' ) ) {
+ throw new Exception( __( 'The payment gateway for this order does not support automatic refunds.', 'woocommerce' ) );
+ }
+
+ $result = $gateway->process_refund( $order->get_id(), $amount, $reason );
+
+ if ( ! $result ) {
+ throw new Exception( __( 'An error occurred while attempting to create the refund using the payment gateway API.', 'woocommerce' ) );
+ }
+
+ if ( is_wp_error( $result ) ) {
+ throw new Exception( $result->get_error_message() );
+ }
+
+ return true;
+
+ } catch ( Exception $e ) {
+ return new WP_Error( 'error', $e->getMessage() );
+ }
+}
+
+/**
+ * Restock items during refund.
+ *
+ * @since 3.0.0
+ * @param WC_Order $order Order instance.
+ * @param array $refunded_line_items Refunded items list.
+ */
+function wc_restock_refunded_items( $order, $refunded_line_items ) {
+ if ( ! apply_filters( 'woocommerce_can_restock_refunded_items', true, $order, $refunded_line_items ) ) {
+ return;
+ }
+
+ $line_items = $order->get_items();
+
+ foreach ( $line_items as $item_id => $item ) {
+ if ( ! isset( $refunded_line_items[ $item_id ], $refunded_line_items[ $item_id ]['qty'] ) ) {
+ continue;
+ }
+ $product = $item->get_product();
+ $item_stock_reduced = $item->get_meta( '_reduced_stock', true );
+ $qty_to_refund = $refunded_line_items[ $item_id ]['qty'];
+
+ if ( ! $item_stock_reduced || ! $qty_to_refund || ! $product || ! $product->managing_stock() ) {
+ continue;
+ }
+
+ $old_stock = $product->get_stock_quantity();
+ $new_stock = wc_update_product_stock( $product, $qty_to_refund, 'increase' );
+
+ // Update _reduced_stock meta to track changes.
+ $item_stock_reduced = $item_stock_reduced - $qty_to_refund;
+
+ if ( 0 < $item_stock_reduced ) {
+ $item->update_meta_data( '_reduced_stock', $item_stock_reduced );
+ } else {
+ $item->delete_meta_data( '_reduced_stock' );
+ }
+
+ /* translators: 1: product ID 2: old stock level 3: new stock level */
+ $order->add_order_note( sprintf( __( 'Item #%1$s stock increased from %2$s to %3$s.', 'woocommerce' ), $product->get_id(), $old_stock, $new_stock ) );
+
+ $item->save();
+
+ do_action( 'woocommerce_restock_refunded_item', $product->get_id(), $old_stock, $new_stock, $order, $product );
+ }
+}
+
+/**
+ * Get tax class by tax id.
+ *
+ * @since 2.2
+ * @param int $tax_id Tax ID.
+ * @return string
+ */
+function wc_get_tax_class_by_tax_id( $tax_id ) {
+ global $wpdb;
+ return $wpdb->get_var( $wpdb->prepare( "SELECT tax_rate_class FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %d", $tax_id ) );
+}
+
+/**
+ * Get payment gateway class by order data.
+ *
+ * @since 2.2
+ * @param int|WC_Order $order Order instance.
+ * @return WC_Payment_Gateway|bool
+ */
+function wc_get_payment_gateway_by_order( $order ) {
+ if ( WC()->payment_gateways() ) {
+ $payment_gateways = WC()->payment_gateways()->payment_gateways();
+ } else {
+ $payment_gateways = array();
+ }
+
+ if ( ! is_object( $order ) ) {
+ $order_id = absint( $order );
+ $order = wc_get_order( $order_id );
+ }
+
+ return is_a( $order, 'WC_Order' ) && isset( $payment_gateways[ $order->get_payment_method() ] ) ? $payment_gateways[ $order->get_payment_method() ] : false;
+}
+
+/**
+ * When refunding an order, create a refund line item if the partial refunds do not match order total.
+ *
+ * This is manual; no gateway refund will be performed.
+ *
+ * @since 2.4
+ * @param int $order_id Order ID.
+ */
+function wc_order_fully_refunded( $order_id ) {
+ $order = wc_get_order( $order_id );
+ $max_refund = wc_format_decimal( $order->get_total() - $order->get_total_refunded() );
+
+ if ( ! $max_refund ) {
+ return;
+ }
+
+ // Create the refund object.
+ wc_switch_to_site_locale();
+ wc_create_refund(
+ array(
+ 'amount' => $max_refund,
+ 'reason' => __( 'Order fully refunded.', 'woocommerce' ),
+ 'order_id' => $order_id,
+ 'line_items' => array(),
+ )
+ );
+ wc_restore_locale();
+
+ $order->add_order_note( __( 'Order status set to refunded. To return funds to the customer you will need to issue a refund through your payment gateway.', 'woocommerce' ) );
+}
+add_action( 'woocommerce_order_status_refunded', 'wc_order_fully_refunded' );
+
+/**
+ * Search orders.
+ *
+ * @since 2.6.0
+ * @param string $term Term to search.
+ * @return array List of orders ID.
+ */
+function wc_order_search( $term ) {
+ $data_store = WC_Data_Store::load( 'order' );
+ return $data_store->search_orders( str_replace( 'Order #', '', wc_clean( $term ) ) );
+}
+
+/**
+ * Update total sales amount for each product within a paid order.
+ *
+ * @since 3.0.0
+ * @param int $order_id Order ID.
+ */
+function wc_update_total_sales_counts( $order_id ) {
+ $order = wc_get_order( $order_id );
+
+ if ( ! $order || $order->get_data_store()->get_recorded_sales( $order ) ) {
+ return;
+ }
+
+ if ( count( $order->get_items() ) > 0 ) {
+ foreach ( $order->get_items() as $item ) {
+ $product_id = $item->get_product_id();
+
+ if ( $product_id ) {
+ $data_store = WC_Data_Store::load( 'product' );
+ $data_store->update_product_sales( $product_id, absint( $item->get_quantity() ), 'increase' );
+ }
+ }
+ }
+
+ $order->get_data_store()->set_recorded_sales( $order, true );
+
+ /**
+ * Called when sales for an order are recorded
+ *
+ * @param int $order_id order id
+ */
+ do_action( 'woocommerce_recorded_sales', $order_id );
+}
+add_action( 'woocommerce_order_status_completed', 'wc_update_total_sales_counts' );
+add_action( 'woocommerce_order_status_processing', 'wc_update_total_sales_counts' );
+add_action( 'woocommerce_order_status_on-hold', 'wc_update_total_sales_counts' );
+
+/**
+ * Update used coupon amount for each coupon within an order.
+ *
+ * @since 3.0.0
+ * @param int $order_id Order ID.
+ */
+function wc_update_coupon_usage_counts( $order_id ) {
+ $order = wc_get_order( $order_id );
+
+ if ( ! $order ) {
+ return;
+ }
+
+ $has_recorded = $order->get_data_store()->get_recorded_coupon_usage_counts( $order );
+
+ if ( $order->has_status( 'cancelled' ) && $has_recorded ) {
+ $action = 'reduce';
+ $order->get_data_store()->set_recorded_coupon_usage_counts( $order, false );
+ } elseif ( ! $order->has_status( 'cancelled' ) && ! $has_recorded ) {
+ $action = 'increase';
+ $order->get_data_store()->set_recorded_coupon_usage_counts( $order, true );
+ } elseif ( $order->has_status( 'cancelled' ) ) {
+ $order->get_data_store()->release_held_coupons( $order, true );
+ return;
+ } else {
+ return;
+ }
+
+ if ( count( $order->get_coupon_codes() ) > 0 ) {
+ foreach ( $order->get_coupon_codes() as $code ) {
+ if ( ! $code ) {
+ continue;
+ }
+
+ $coupon = new WC_Coupon( $code );
+ $used_by = $order->get_user_id();
+
+ if ( ! $used_by ) {
+ $used_by = $order->get_billing_email();
+ }
+
+ switch ( $action ) {
+ case 'reduce':
+ $coupon->decrease_usage_count( $used_by );
+ break;
+ case 'increase':
+ $coupon->increase_usage_count( $used_by, $order );
+ break;
+ }
+ }
+ $order->get_data_store()->release_held_coupons( $order, true );
+ }
+}
+add_action( 'woocommerce_order_status_pending', 'wc_update_coupon_usage_counts' );
+add_action( 'woocommerce_order_status_completed', 'wc_update_coupon_usage_counts' );
+add_action( 'woocommerce_order_status_processing', 'wc_update_coupon_usage_counts' );
+add_action( 'woocommerce_order_status_on-hold', 'wc_update_coupon_usage_counts' );
+add_action( 'woocommerce_order_status_cancelled', 'wc_update_coupon_usage_counts' );
+
+/**
+ * Cancel all unpaid orders after held duration to prevent stock lock for those products.
+ */
+function wc_cancel_unpaid_orders() {
+ $held_duration = get_option( 'woocommerce_hold_stock_minutes' );
+
+ if ( $held_duration < 1 || 'yes' !== get_option( 'woocommerce_manage_stock' ) ) {
+ return;
+ }
+
+ $data_store = WC_Data_Store::load( 'order' );
+ $unpaid_orders = $data_store->get_unpaid_orders( strtotime( '-' . absint( $held_duration ) . ' MINUTES', current_time( 'timestamp' ) ) );
+
+ if ( $unpaid_orders ) {
+ foreach ( $unpaid_orders as $unpaid_order ) {
+ $order = wc_get_order( $unpaid_order );
+
+ if ( apply_filters( 'woocommerce_cancel_unpaid_order', 'checkout' === $order->get_created_via(), $order ) ) {
+ $order->update_status( 'cancelled', __( 'Unpaid order cancelled - time limit reached.', 'woocommerce' ) );
+ }
+ }
+ }
+ wp_clear_scheduled_hook( 'woocommerce_cancel_unpaid_orders' );
+ wp_schedule_single_event( time() + ( absint( $held_duration ) * 60 ), 'woocommerce_cancel_unpaid_orders' );
+}
+add_action( 'woocommerce_cancel_unpaid_orders', 'wc_cancel_unpaid_orders' );
+
+/**
+ * Sanitize order id removing unwanted characters.
+ *
+ * E.g Users can sometimes try to track an order id using # with no success.
+ * This function will fix this.
+ *
+ * @since 3.1.0
+ * @param int $order_id Order ID.
+ */
+function wc_sanitize_order_id( $order_id ) {
+ return (int) filter_var( $order_id, FILTER_SANITIZE_NUMBER_INT );
+}
+add_filter( 'woocommerce_shortcode_order_tracking_order_id', 'wc_sanitize_order_id' );
+
+/**
+ * Get an order note.
+ *
+ * @since 3.2.0
+ * @param int|WP_Comment $data Note ID (or WP_Comment instance for internal use only).
+ * @return stdClass|null Object with order note details or null when does not exists.
+ */
+function wc_get_order_note( $data ) {
+ if ( is_numeric( $data ) ) {
+ $data = get_comment( $data );
+ }
+
+ if ( ! is_a( $data, 'WP_Comment' ) ) {
+ return null;
+ }
+
+ return (object) apply_filters(
+ 'woocommerce_get_order_note',
+ array(
+ 'id' => (int) $data->comment_ID,
+ 'date_created' => wc_string_to_datetime( $data->comment_date ),
+ 'content' => $data->comment_content,
+ 'customer_note' => (bool) get_comment_meta( $data->comment_ID, 'is_customer_note', true ),
+ 'added_by' => __( 'WooCommerce', 'woocommerce' ) === $data->comment_author ? 'system' : $data->comment_author,
+ ),
+ $data
+ );
+}
+
+/**
+ * Get order notes.
+ *
+ * @since 3.2.0
+ * @param array $args Query arguments {
+ * Array of query parameters.
+ *
+ * @type string $limit Maximum number of notes to retrieve.
+ * Default empty (no limit).
+ * @type int $order_id Limit results to those affiliated with a given order ID.
+ * Default 0.
+ * @type array $order__in Array of order IDs to include affiliated notes for.
+ * Default empty.
+ * @type array $order__not_in Array of order IDs to exclude affiliated notes for.
+ * Default empty.
+ * @type string $orderby Define how should sort notes.
+ * Accepts 'date_created', 'date_created_gmt' or 'id'.
+ * Default: 'id'.
+ * @type string $order How to order retrieved notes.
+ * Accepts 'ASC' or 'DESC'.
+ * Default: 'DESC'.
+ * @type string $type Define what type of note should retrieve.
+ * Accepts 'customer', 'internal' or empty for both.
+ * Default empty.
+ * }
+ * @return stdClass[] Array of stdClass objects with order notes details.
+ */
+function wc_get_order_notes( $args ) {
+ $key_mapping = array(
+ 'limit' => 'number',
+ 'order_id' => 'post_id',
+ 'order__in' => 'post__in',
+ 'order__not_in' => 'post__not_in',
+ );
+
+ foreach ( $key_mapping as $query_key => $db_key ) {
+ if ( isset( $args[ $query_key ] ) ) {
+ $args[ $db_key ] = $args[ $query_key ];
+ unset( $args[ $query_key ] );
+ }
+ }
+
+ // Define orderby.
+ $orderby_mapping = array(
+ 'date_created' => 'comment_date',
+ 'date_created_gmt' => 'comment_date_gmt',
+ 'id' => 'comment_ID',
+ );
+
+ $args['orderby'] = ! empty( $args['orderby'] ) && in_array( $args['orderby'], array( 'date_created', 'date_created_gmt', 'id' ), true ) ? $orderby_mapping[ $args['orderby'] ] : 'comment_ID';
+
+ // Set WooCommerce order type.
+ if ( isset( $args['type'] ) && 'customer' === $args['type'] ) {
+ $args['meta_query'] = array( // WPCS: slow query ok.
+ array(
+ 'key' => 'is_customer_note',
+ 'value' => 1,
+ 'compare' => '=',
+ ),
+ );
+ } elseif ( isset( $args['type'] ) && 'internal' === $args['type'] ) {
+ $args['meta_query'] = array( // WPCS: slow query ok.
+ array(
+ 'key' => 'is_customer_note',
+ 'compare' => 'NOT EXISTS',
+ ),
+ );
+ }
+
+ // Set correct comment type.
+ $args['type'] = 'order_note';
+
+ // Always approved.
+ $args['status'] = 'approve';
+
+ // Does not support 'count' or 'fields'.
+ unset( $args['count'], $args['fields'] );
+
+ remove_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ), 10, 1 );
+
+ $notes = get_comments( $args );
+
+ add_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ), 10, 1 );
+
+ return array_filter( array_map( 'wc_get_order_note', $notes ) );
+}
+
+/**
+ * Create an order note.
+ *
+ * @since 3.2.0
+ * @param int $order_id Order ID.
+ * @param string $note Note to add.
+ * @param bool $is_customer_note If is a costumer note.
+ * @param bool $added_by_user If note is create by an user.
+ * @return int|WP_Error Integer when created or WP_Error when found an error.
+ */
+function wc_create_order_note( $order_id, $note, $is_customer_note = false, $added_by_user = false ) {
+ $order = wc_get_order( $order_id );
+
+ if ( ! $order ) {
+ return new WP_Error( 'invalid_order_id', __( 'Invalid order ID.', 'woocommerce' ), array( 'status' => 400 ) );
+ }
+
+ return $order->add_order_note( $note, (int) $is_customer_note, $added_by_user );
+}
+
+/**
+ * Delete an order note.
+ *
+ * @since 3.2.0
+ * @param int $note_id Order note.
+ * @return bool True on success, false on failure.
+ */
+function wc_delete_order_note( $note_id ) {
+ return wp_delete_comment( $note_id, true );
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-order-item-functions.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-order-item-functions.php
new file mode 100644
index 0000000..5f7c6a1
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-order-item-functions.php
@@ -0,0 +1,181 @@
+ '',
+ 'order_item_type' => 'line_item',
+ );
+
+ $item_array = wp_parse_args( $item_array, $defaults );
+ $data_store = WC_Data_Store::load( 'order-item' );
+ $item_id = $data_store->add_order_item( $order_id, $item_array );
+ $item = WC_Order_Factory::get_order_item( $item_id );
+
+ do_action( 'woocommerce_new_order_item', $item_id, $item, $order_id );
+
+ return $item_id;
+}
+
+/**
+ * Update an item for an order.
+ *
+ * @since 2.2
+ * @param int $item_id Item ID.
+ * @param array $args Either `order_item_type` or `order_item_name`.
+ *
+ * @throws Exception When `WC_Data_Store::load` validation fails.
+ * @return bool True if successfully updated, false otherwise.
+ */
+function wc_update_order_item( $item_id, $args ) {
+ $data_store = WC_Data_Store::load( 'order-item' );
+ $update = $data_store->update_order_item( $item_id, $args );
+
+ if ( false === $update ) {
+ return false;
+ }
+
+ do_action( 'woocommerce_update_order_item', $item_id, $args );
+
+ return true;
+}
+
+/**
+ * Delete an item from the order it belongs to based on item id.
+ *
+ * @param int $item_id Item ID.
+ *
+ * @throws Exception When `WC_Data_Store::load` validation fails.
+ * @return bool
+ */
+function wc_delete_order_item( $item_id ) {
+ $item_id = absint( $item_id );
+
+ if ( ! $item_id ) {
+ return false;
+ }
+
+ $data_store = WC_Data_Store::load( 'order-item' );
+
+ do_action( 'woocommerce_before_delete_order_item', $item_id );
+
+ $data_store->delete_order_item( $item_id );
+
+ do_action( 'woocommerce_delete_order_item', $item_id );
+
+ return true;
+}
+
+/**
+ * WooCommerce Order Item Meta API - Update term meta.
+ *
+ * @param int $item_id Item ID.
+ * @param string $meta_key Meta key.
+ * @param string $meta_value Meta value.
+ * @param string $prev_value Previous value (default: '').
+ *
+ * @throws Exception When `WC_Data_Store::load` validation fails.
+ * @return bool
+ */
+function wc_update_order_item_meta( $item_id, $meta_key, $meta_value, $prev_value = '' ) {
+ $data_store = WC_Data_Store::load( 'order-item' );
+ if ( $data_store->update_metadata( $item_id, $meta_key, $meta_value, $prev_value ) ) {
+ WC_Cache_Helper::invalidate_cache_group( 'object_' . $item_id ); // Invalidate cache.
+ return true;
+ }
+ return false;
+}
+
+/**
+ * WooCommerce Order Item Meta API - Add term meta.
+ *
+ * @param int $item_id Item ID.
+ * @param string $meta_key Meta key.
+ * @param string $meta_value Meta value.
+ * @param bool $unique If meta data should be unique (default: false).
+ *
+ * @throws Exception When `WC_Data_Store::load` validation fails.
+ * @return int New row ID or 0.
+ */
+function wc_add_order_item_meta( $item_id, $meta_key, $meta_value, $unique = false ) {
+ $data_store = WC_Data_Store::load( 'order-item' );
+ $meta_id = $data_store->add_metadata( $item_id, $meta_key, $meta_value, $unique );
+
+ if ( $meta_id ) {
+ WC_Cache_Helper::invalidate_cache_group( 'object_' . $item_id ); // Invalidate cache.
+ return $meta_id;
+ }
+ return 0;
+}
+
+/**
+ * WooCommerce Order Item Meta API - Delete term meta.
+ *
+ * @param int $item_id Item ID.
+ * @param string $meta_key Meta key.
+ * @param string $meta_value Meta value (default: '').
+ * @param bool $delete_all Delete all meta data, defaults to `false`.
+ *
+ * @throws Exception When `WC_Data_Store::load` validation fails.
+ * @return bool
+ */
+function wc_delete_order_item_meta( $item_id, $meta_key, $meta_value = '', $delete_all = false ) {
+ $data_store = WC_Data_Store::load( 'order-item' );
+ if ( $data_store->delete_metadata( $item_id, $meta_key, $meta_value, $delete_all ) ) {
+ WC_Cache_Helper::invalidate_cache_group( 'object_' . $item_id ); // Invalidate cache.
+ return true;
+ }
+ return false;
+}
+
+/**
+ * WooCommerce Order Item Meta API - Get term meta.
+ *
+ * @param int $item_id Item ID.
+ * @param string $key Meta key.
+ * @param bool $single Whether to return a single value. (default: true).
+ *
+ * @throws Exception When `WC_Data_Store::load` validation fails.
+ * @return mixed
+ */
+function wc_get_order_item_meta( $item_id, $key, $single = true ) {
+ $data_store = WC_Data_Store::load( 'order-item' );
+ return $data_store->get_metadata( $item_id, $key, $single );
+}
+
+/**
+ * Get order ID by order item ID.
+ *
+ * @param int $item_id Item ID.
+ *
+ * @throws Exception When `WC_Data_Store::load` validation fails.
+ * @return int
+ */
+function wc_get_order_id_by_order_item_id( $item_id ) {
+ $data_store = WC_Data_Store::load( 'order-item' );
+ return $data_store->get_order_id_by_order_item_id( $item_id );
+}
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-page-functions.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-page-functions.php
new file mode 100644
index 0000000..7519db9
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-page-functions.php
@@ -0,0 +1,227 @@
+query->get_current_endpoint();
+ $action = isset( $_GET['action'] ) ? sanitize_text_field( wp_unslash( $_GET['action'] ) ) : '';
+ $endpoint_title = WC()->query->get_endpoint_title( $endpoint, $action );
+ $title = $endpoint_title ? $endpoint_title : $title;
+
+ remove_filter( 'the_title', 'wc_page_endpoint_title' );
+ }
+
+ return $title;
+}
+
+add_filter( 'the_title', 'wc_page_endpoint_title' );
+
+/**
+ * Retrieve page ids - used for myaccount, edit_address, shop, cart, checkout, pay, view_order, terms. returns -1 if no page is found.
+ *
+ * @param string $page Page slug.
+ * @return int
+ */
+function wc_get_page_id( $page ) {
+ if ( 'pay' === $page || 'thanks' === $page ) {
+ wc_deprecated_argument( __FUNCTION__, '2.1', 'The "pay" and "thanks" pages are no-longer used - an endpoint is added to the checkout instead. To get a valid link use the WC_Order::get_checkout_payment_url() or WC_Order::get_checkout_order_received_url() methods instead.' );
+
+ $page = 'checkout';
+ }
+ if ( 'change_password' === $page || 'edit_address' === $page || 'lost_password' === $page ) {
+ wc_deprecated_argument( __FUNCTION__, '2.1', 'The "change_password", "edit_address" and "lost_password" pages are no-longer used - an endpoint is added to the my-account instead. To get a valid link use the wc_customer_edit_account_url() function instead.' );
+
+ $page = 'myaccount';
+ }
+
+ $page = apply_filters( 'woocommerce_get_' . $page . '_page_id', get_option( 'woocommerce_' . $page . '_page_id' ) );
+
+ return $page ? absint( $page ) : -1;
+}
+
+/**
+ * Retrieve page permalink.
+ *
+ * @param string $page page slug.
+ * @param string|bool $fallback Fallback URL if page is not set. Defaults to home URL. @since 3.4.0.
+ * @return string
+ */
+function wc_get_page_permalink( $page, $fallback = null ) {
+ $page_id = wc_get_page_id( $page );
+ $permalink = 0 < $page_id ? get_permalink( $page_id ) : '';
+
+ if ( ! $permalink ) {
+ $permalink = is_null( $fallback ) ? get_home_url() : $fallback;
+ }
+
+ return apply_filters( 'woocommerce_get_' . $page . '_page_permalink', $permalink );
+}
+
+/**
+ * Get endpoint URL.
+ *
+ * Gets the URL for an endpoint, which varies depending on permalink settings.
+ *
+ * @param string $endpoint Endpoint slug.
+ * @param string $value Query param value.
+ * @param string $permalink Permalink.
+ *
+ * @return string
+ */
+function wc_get_endpoint_url( $endpoint, $value = '', $permalink = '' ) {
+ if ( ! $permalink ) {
+ $permalink = get_permalink();
+ }
+
+ // Map endpoint to options.
+ $query_vars = WC()->query->get_query_vars();
+ $endpoint = ! empty( $query_vars[ $endpoint ] ) ? $query_vars[ $endpoint ] : $endpoint;
+ $value = ( get_option( 'woocommerce_myaccount_edit_address_endpoint', 'edit-address' ) === $endpoint ) ? wc_edit_address_i18n( $value ) : $value;
+
+ if ( get_option( 'permalink_structure' ) ) {
+ if ( strstr( $permalink, '?' ) ) {
+ $query_string = '?' . wp_parse_url( $permalink, PHP_URL_QUERY );
+ $permalink = current( explode( '?', $permalink ) );
+ } else {
+ $query_string = '';
+ }
+ $url = trailingslashit( $permalink );
+
+ if ( $value ) {
+ $url .= trailingslashit( $endpoint ) . user_trailingslashit( $value );
+ } else {
+ $url .= user_trailingslashit( $endpoint );
+ }
+
+ $url .= $query_string;
+ } else {
+ $url = add_query_arg( $endpoint, $value, $permalink );
+ }
+
+ return apply_filters( 'woocommerce_get_endpoint_url', $url, $endpoint, $value, $permalink );
+}
+
+/**
+ * Hide menu items conditionally.
+ *
+ * @param array $items Navigation items.
+ * @return array
+ */
+function wc_nav_menu_items( $items ) {
+ if ( ! is_user_logged_in() ) {
+ $customer_logout = get_option( 'woocommerce_logout_endpoint', 'customer-logout' );
+
+ if ( ! empty( $customer_logout ) && ! empty( $items ) && is_array( $items ) ) {
+ foreach ( $items as $key => $item ) {
+ if ( empty( $item->url ) ) {
+ continue;
+ }
+ $path = wp_parse_url( $item->url, PHP_URL_PATH );
+ $query = wp_parse_url( $item->url, PHP_URL_QUERY );
+
+ if ( strstr( $path, $customer_logout ) || strstr( $query, $customer_logout ) ) {
+ unset( $items[ $key ] );
+ }
+ }
+ }
+ }
+
+ return $items;
+}
+add_filter( 'wp_nav_menu_objects', 'wc_nav_menu_items', 10 );
+
+
+/**
+ * Fix active class in nav for shop page.
+ *
+ * @param array $menu_items Menu items.
+ * @return array
+ */
+function wc_nav_menu_item_classes( $menu_items ) {
+ if ( ! is_woocommerce() ) {
+ return $menu_items;
+ }
+
+ $shop_page = wc_get_page_id( 'shop' );
+ $page_for_posts = (int) get_option( 'page_for_posts' );
+
+ if ( ! empty( $menu_items ) && is_array( $menu_items ) ) {
+ foreach ( $menu_items as $key => $menu_item ) {
+ $classes = (array) $menu_item->classes;
+ $menu_id = (int) $menu_item->object_id;
+
+ // Unset active class for blog page.
+ if ( $page_for_posts === $menu_id ) {
+ $menu_items[ $key ]->current = false;
+
+ if ( in_array( 'current_page_parent', $classes, true ) ) {
+ unset( $classes[ array_search( 'current_page_parent', $classes, true ) ] );
+ }
+
+ if ( in_array( 'current-menu-item', $classes, true ) ) {
+ unset( $classes[ array_search( 'current-menu-item', $classes, true ) ] );
+ }
+ } elseif ( is_shop() && $shop_page === $menu_id && 'page' === $menu_item->object ) {
+ // Set active state if this is the shop page link.
+ $menu_items[ $key ]->current = true;
+ $classes[] = 'current-menu-item';
+ $classes[] = 'current_page_item';
+
+ } elseif ( is_singular( 'product' ) && $shop_page === $menu_id ) {
+ // Set parent state if this is a product page.
+ $classes[] = 'current_page_parent';
+ }
+
+ $menu_items[ $key ]->classes = array_unique( $classes );
+ }
+ }
+
+ return $menu_items;
+}
+add_filter( 'wp_nav_menu_objects', 'wc_nav_menu_item_classes', 2 );
+
+
+/**
+ * Fix active class in wp_list_pages for shop page.
+ *
+ * See details in https://github.com/woocommerce/woocommerce/issues/177.
+ *
+ * @param string $pages Pages list.
+ * @return string
+ */
+function wc_list_pages( $pages ) {
+ if ( ! is_woocommerce() ) {
+ return $pages;
+ }
+
+ // Remove current_page_parent class from any item.
+ $pages = str_replace( 'current_page_parent', '', $pages );
+ // Find shop_page_id through woocommerce options.
+ $shop_page = 'page-item-' . wc_get_page_id( 'shop' );
+
+ if ( is_shop() ) {
+ // Add current_page_item class to shop page.
+ return str_replace( $shop_page, $shop_page . ' current_page_item', $pages );
+ }
+
+ // Add current_page_parent class to shop page.
+ return str_replace( $shop_page, $shop_page . ' current_page_parent', $pages );
+}
+add_filter( 'wp_list_pages', 'wc_list_pages' );
diff --git a/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-product-functions.php b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-product-functions.php
new file mode 100644
index 0000000..d4ee945
--- /dev/null
+++ b/TE2/Proyecto Teknovate/htdocs/wordpress/wp-content/plugins/woocommerce/includes/wc-product-functions.php
@@ -0,0 +1,1612 @@
+ 'limit',
+ 'post_status' => 'status',
+ 'post_parent' => 'parent',
+ 'posts_per_page' => 'limit',
+ 'paged' => 'page',
+ );
+
+ foreach ( $map_legacy as $from => $to ) {
+ if ( isset( $args[ $from ] ) ) {
+ $args[ $to ] = $args[ $from ];
+ }
+ }
+
+ $query = new WC_Product_Query( $args );
+ return $query->get_products();
+}
+
+/**
+ * Main function for returning products, uses the WC_Product_Factory class.
+ *
+ * This function should only be called after 'init' action is finished, as there might be taxonomies that are getting
+ * registered during the init action.
+ *
+ * @since 2.2.0
+ *
+ * @param mixed $the_product Post object or post ID of the product.
+ * @param array $deprecated Previously used to pass arguments to the factory, e.g. to force a type.
+ * @return WC_Product|null|false
+ */
+function wc_get_product( $the_product = false, $deprecated = array() ) {
+ if ( ! did_action( 'woocommerce_init' ) || ! did_action( 'woocommerce_after_register_taxonomy' ) || ! did_action( 'woocommerce_after_register_post_type' ) ) {
+ /* translators: 1: wc_get_product 2: woocommerce_init 3: woocommerce_after_register_taxonomy 4: woocommerce_after_register_post_type */
+ wc_doing_it_wrong( __FUNCTION__, sprintf( __( '%1$s should not be called before the %2$s, %3$s and %4$s actions have finished.', 'woocommerce' ), 'wc_get_product', 'woocommerce_init', 'woocommerce_after_register_taxonomy', 'woocommerce_after_register_post_type' ), '3.9' );
+ return false;
+ }
+ if ( ! empty( $deprecated ) ) {
+ wc_deprecated_argument( 'args', '3.0', 'Passing args to wc_get_product is deprecated. If you need to force a type, construct the product class directly.' );
+ }
+ return WC()->product_factory->get_product( $the_product, $deprecated );
+}
+
+/**
+ * Get a product object.
+ *
+ * @see WC_Product_Factory::get_product_classname
+ * @since 3.9.0
+ * @param string $product_type Product type. If used an invalid type a WC_Product_Simple instance will be returned.
+ * @param int $product_id Product ID.
+ * @return WC_Product
+ */
+function wc_get_product_object( $product_type, $product_id = 0 ) {
+ $classname = WC_Product_Factory::get_product_classname( $product_id, $product_type );
+
+ return new $classname( $product_id );
+}
+
+/**
+ * Returns whether or not SKUS are enabled.
+ *
+ * @return bool
+ */
+function wc_product_sku_enabled() {
+ return apply_filters( 'wc_product_sku_enabled', true );
+}
+
+/**
+ * Returns whether or not product weights are enabled.
+ *
+ * @return bool
+ */
+function wc_product_weight_enabled() {
+ return apply_filters( 'wc_product_weight_enabled', true );
+}
+
+/**
+ * Returns whether or not product dimensions (HxWxD) are enabled.
+ *
+ * @return bool
+ */
+function wc_product_dimensions_enabled() {
+ return apply_filters( 'wc_product_dimensions_enabled', true );
+}
+
+/**
+ * Clear transient cache for product data.
+ *
+ * @param int $post_id (default: 0) The product ID.
+ */
+function wc_delete_product_transients( $post_id = 0 ) {
+ // Transient data to clear with a fixed name which may be stale after product updates.
+ $transients_to_clear = array(
+ 'wc_products_onsale',
+ 'wc_featured_products',
+ 'wc_outofstock_count',
+ 'wc_low_stock_count',
+ );
+
+ foreach ( $transients_to_clear as $transient ) {
+ delete_transient( $transient );
+ }
+
+ if ( $post_id > 0 ) {
+ // Transient names that include an ID - since they are dynamic they cannot be cleaned in bulk without the ID.
+ $post_transient_names = array(
+ 'wc_product_children_',
+ 'wc_var_prices_',
+ 'wc_related_',
+ 'wc_child_has_weight_',
+ 'wc_child_has_dimensions_',
+ );
+
+ foreach ( $post_transient_names as $transient ) {
+ delete_transient( $transient . $post_id );
+ }
+ }
+
+ // Increments the transient version to invalidate cache.
+ WC_Cache_Helper::get_transient_version( 'product', true );
+
+ do_action( 'woocommerce_delete_product_transients', $post_id );
+}
+
+/**
+ * Function that returns an array containing the IDs of the products that are on sale.
+ *
+ * @since 2.0
+ * @return array
+ */
+function wc_get_product_ids_on_sale() {
+ // Load from cache.
+ $product_ids_on_sale = get_transient( 'wc_products_onsale' );
+
+ // Valid cache found.
+ if ( false !== $product_ids_on_sale ) {
+ return $product_ids_on_sale;
+ }
+
+ $data_store = WC_Data_Store::load( 'product' );
+ $on_sale_products = $data_store->get_on_sale_products();
+ $product_ids_on_sale = wp_parse_id_list( array_merge( wp_list_pluck( $on_sale_products, 'id' ), array_diff( wp_list_pluck( $on_sale_products, 'parent_id' ), array( 0 ) ) ) );
+
+ set_transient( 'wc_products_onsale', $product_ids_on_sale, DAY_IN_SECONDS * 30 );
+
+ return $product_ids_on_sale;
+}
+
+/**
+ * Function that returns an array containing the IDs of the featured products.
+ *
+ * @since 2.1
+ * @return array
+ */
+function wc_get_featured_product_ids() {
+ // Load from cache.
+ $featured_product_ids = get_transient( 'wc_featured_products' );
+
+ // Valid cache found.
+ if ( false !== $featured_product_ids ) {
+ return $featured_product_ids;
+ }
+
+ $data_store = WC_Data_Store::load( 'product' );
+ $featured = $data_store->get_featured_product_ids();
+ $product_ids = array_keys( $featured );
+ $parent_ids = array_values( array_filter( $featured ) );
+ $featured_product_ids = array_unique( array_merge( $product_ids, $parent_ids ) );
+
+ set_transient( 'wc_featured_products', $featured_product_ids, DAY_IN_SECONDS * 30 );
+
+ return $featured_product_ids;
+}
+
+/**
+ * Filter to allow product_cat in the permalinks for products.
+ *
+ * @param string $permalink The existing permalink URL.
+ * @param WP_Post $post WP_Post object.
+ * @return string
+ */
+function wc_product_post_type_link( $permalink, $post ) {
+ // Abort if post is not a product.
+ if ( 'product' !== $post->post_type ) {
+ return $permalink;
+ }
+
+ // Abort early if the placeholder rewrite tag isn't in the generated URL.
+ if ( false === strpos( $permalink, '%' ) ) {
+ return $permalink;
+ }
+
+ // Get the custom taxonomy terms in use by this post.
+ $terms = get_the_terms( $post->ID, 'product_cat' );
+
+ if ( ! empty( $terms ) ) {
+ $terms = wp_list_sort(
+ $terms,
+ array(
+ 'parent' => 'DESC',
+ 'term_id' => 'ASC',
+ )
+ );
+ $category_object = apply_filters( 'wc_product_post_type_link_product_cat', $terms[0], $terms, $post );
+ $product_cat = $category_object->slug;
+
+ if ( $category_object->parent ) {
+ $ancestors = get_ancestors( $category_object->term_id, 'product_cat' );
+ foreach ( $ancestors as $ancestor ) {
+ $ancestor_object = get_term( $ancestor, 'product_cat' );
+ if ( apply_filters( 'woocommerce_product_post_type_link_parent_category_only', false ) ) {
+ $product_cat = $ancestor_object->slug;
+ } else {
+ $product_cat = $ancestor_object->slug . '/' . $product_cat;
+ }
+ }
+ }
+ } else {
+ // If no terms are assigned to this post, use a string instead (can't leave the placeholder there).
+ $product_cat = _x( 'uncategorized', 'slug', 'woocommerce' );
+ }
+
+ $find = array(
+ '%year%',
+ '%monthnum%',
+ '%day%',
+ '%hour%',
+ '%minute%',
+ '%second%',
+ '%post_id%',
+ '%category%',
+ '%product_cat%',
+ );
+
+ $replace = array(
+ date_i18n( 'Y', strtotime( $post->post_date ) ),
+ date_i18n( 'm', strtotime( $post->post_date ) ),
+ date_i18n( 'd', strtotime( $post->post_date ) ),
+ date_i18n( 'H', strtotime( $post->post_date ) ),
+ date_i18n( 'i', strtotime( $post->post_date ) ),
+ date_i18n( 's', strtotime( $post->post_date ) ),
+ $post->ID,
+ $product_cat,
+ $product_cat,
+ );
+
+ $permalink = str_replace( $find, $replace, $permalink );
+
+ return $permalink;
+}
+add_filter( 'post_type_link', 'wc_product_post_type_link', 10, 2 );
+
+/**
+ * Get the placeholder image URL either from media, or use the fallback image.
+ *
+ * @param string $size Thumbnail size to use.
+ * @return string
+ */
+function wc_placeholder_img_src( $size = 'woocommerce_thumbnail' ) {
+ $src = WC()->plugin_url() . '/assets/images/placeholder.png';
+ $placeholder_image = get_option( 'woocommerce_placeholder_image', 0 );
+
+ if ( ! empty( $placeholder_image ) ) {
+ if ( is_numeric( $placeholder_image ) ) {
+ $image = wp_get_attachment_image_src( $placeholder_image, $size );
+
+ if ( ! empty( $image[0] ) ) {
+ $src = $image[0];
+ }
+ } else {
+ $src = $placeholder_image;
+ }
+ }
+
+ return apply_filters( 'woocommerce_placeholder_img_src', $src );
+}
+
+/**
+ * Get the placeholder image.
+ *
+ * Uses wp_get_attachment_image if using an attachment ID @since 3.6.0 to handle responsiveness.
+ *
+ * @param string $size Image size.
+ * @param string|array $attr Optional. Attributes for the image markup. Default empty.
+ * @return string
+ */
+function wc_placeholder_img( $size = 'woocommerce_thumbnail', $attr = '' ) {
+ $dimensions = wc_get_image_size( $size );
+ $placeholder_image = get_option( 'woocommerce_placeholder_image', 0 );
+
+ $default_attr = array(
+ 'class' => 'woocommerce-placeholder wp-post-image',
+ 'alt' => __( 'Placeholder', 'woocommerce' ),
+ );
+
+ $attr = wp_parse_args( $attr, $default_attr );
+
+ if ( wp_attachment_is_image( $placeholder_image ) ) {
+ $image_html = wp_get_attachment_image(
+ $placeholder_image,
+ $size,
+ false,
+ $attr
+ );
+ } else {
+ $image = wc_placeholder_img_src( $size );
+ $hwstring = image_hwstring( $dimensions['width'], $dimensions['height'] );
+ $attributes = array();
+
+ foreach ( $attr as $name => $value ) {
+ $attribute[] = esc_attr( $name ) . '="' . esc_attr( $value ) . '"';
+ }
+
+ $image_html = '';
+ }
+
+ return apply_filters( 'woocommerce_placeholder_img', $image_html, $size, $dimensions );
+}
+
+/**
+ * Variation Formatting.
+ *
+ * Gets a formatted version of variation data or item meta.
+ *
+ * @param array|WC_Product_Variation $variation Variation object.
+ * @param bool $flat Should this be a flat list or HTML list? (default: false).
+ * @param bool $include_names include attribute names/labels in the list.
+ * @param bool $skip_attributes_in_name Do not list attributes already part of the variation name.
+ * @return string
+ */
+function wc_get_formatted_variation( $variation, $flat = false, $include_names = true, $skip_attributes_in_name = false ) {
+ $return = '';
+
+ if ( is_a( $variation, 'WC_Product_Variation' ) ) {
+ $variation_attributes = $variation->get_attributes();
+ $product = $variation;
+ $variation_name = $variation->get_name();
+ } else {
+ $product = false;
+ $variation_name = '';
+ // Remove attribute_ prefix from names.
+ $variation_attributes = array();
+ if ( is_array( $variation ) ) {
+ foreach ( $variation as $key => $value ) {
+ $variation_attributes[ str_replace( 'attribute_', '', $key ) ] = $value;
+ }
+ }
+ }
+
+ $list_type = $include_names ? 'dl' : 'ul';
+
+ if ( is_array( $variation_attributes ) ) {
+
+ if ( ! $flat ) {
+ $return = '<' . $list_type . ' class="variation">';
+ }
+
+ $variation_list = array();
+
+ foreach ( $variation_attributes as $name => $value ) {
+ // If this is a term slug, get the term's nice name.
+ if ( taxonomy_exists( $name ) ) {
+ $term = get_term_by( 'slug', $value, $name );
+ if ( ! is_wp_error( $term ) && ! empty( $term->name ) ) {
+ $value = $term->name;
+ }
+ }
+
+ // Do not list attributes already part of the variation name.
+ if ( '' === $value || ( $skip_attributes_in_name && wc_is_attribute_in_product_name( $value, $variation_name ) ) ) {
+ continue;
+ }
+
+ if ( $include_names ) {
+ if ( $flat ) {
+ $variation_list[] = wc_attribute_label( $name, $product ) . ': ' . rawurldecode( $value );
+ } else {
+ $variation_list[] = '
', $notice ); + } +} + +/** + * Loop + */ + +if ( ! function_exists( 'woocommerce_page_title' ) ) { + + /** + * Page Title function. + * + * @param bool $echo Should echo title. + * @return string + */ + function woocommerce_page_title( $echo = true ) { + + if ( is_search() ) { + /* translators: %s: search query */ + $page_title = sprintf( __( 'Search results: “%s”', 'woocommerce' ), get_search_query() ); + + if ( get_query_var( 'paged' ) ) { + /* translators: %s: page number */ + $page_title .= sprintf( __( ' – Page %s', 'woocommerce' ), get_query_var( 'paged' ) ); + } + } elseif ( is_tax() ) { + + $page_title = single_term_title( '', false ); + + } else { + + $shop_page_id = wc_get_page_id( 'shop' ); + $page_title = get_the_title( $shop_page_id ); + + } + + $page_title = apply_filters( 'woocommerce_page_title', $page_title ); + + if ( $echo ) { + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo $page_title; + } else { + return $page_title; + } + } +} + +if ( ! function_exists( 'woocommerce_product_loop_start' ) ) { + + /** + * Output the start of a product loop. By default this is a UL. + * + * @param bool $echo Should echo?. + * @return string + */ + function woocommerce_product_loop_start( $echo = true ) { + ob_start(); + + wc_set_loop_prop( 'loop', 0 ); + + wc_get_template( 'loop/loop-start.php' ); + + $loop_start = apply_filters( 'woocommerce_product_loop_start', ob_get_clean() ); + + if ( $echo ) { + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo $loop_start; + } else { + return $loop_start; + } + } +} + +if ( ! function_exists( 'woocommerce_product_loop_end' ) ) { + + /** + * Output the end of a product loop. By default this is a UL. + * + * @param bool $echo Should echo?. + * @return string + */ + function woocommerce_product_loop_end( $echo = true ) { + ob_start(); + + wc_get_template( 'loop/loop-end.php' ); + + $loop_end = apply_filters( 'woocommerce_product_loop_end', ob_get_clean() ); + + if ( $echo ) { + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo $loop_end; + } else { + return $loop_end; + } + } +} +if ( ! function_exists( 'woocommerce_template_loop_product_title' ) ) { + + /** + * Show the product title in the product loop. By default this is an H2. + */ + function woocommerce_template_loop_product_title() { + echo '
'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + } +} +if ( ! function_exists( 'woocommerce_template_loop_category_title' ) ) { + + /** + * Show the subcategory title in the product loop. + * + * @param object $category Category object. + */ + function woocommerce_template_loop_category_title( $category ) { + ?> +
+ '; + } +} + +if ( ! function_exists( 'woocommerce_template_loop_product_link_close' ) ) { + /** + * Insert the closing anchor tag for products in the loop. + */ + function woocommerce_template_loop_product_link_close() { + echo ''; + } +} + +if ( ! function_exists( 'woocommerce_template_loop_category_link_open' ) ) { + /** + * Insert the opening anchor tag for categories in the loop. + * + * @param int|object|string $category Category ID, Object or String. + */ + function woocommerce_template_loop_category_link_open( $category ) { + echo ''; + } +} + +if ( ! function_exists( 'woocommerce_template_loop_category_link_close' ) ) { + /** + * Insert the closing anchor tag for categories in the loop. + */ + function woocommerce_template_loop_category_link_close() { + echo ''; + } +} + +if ( ! function_exists( 'woocommerce_taxonomy_archive_description' ) ) { + + /** + * Show an archive description on taxonomy archives. + */ + function woocommerce_taxonomy_archive_description() { + if ( is_product_taxonomy() && 0 === absint( get_query_var( 'paged' ) ) ) { + $term = get_queried_object(); + + if ( $term && ! empty( $term->description ) ) { + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo '
'; + } + } + } +} +if ( ! function_exists( 'woocommerce_product_archive_description' ) ) { + + /** + * Show a shop page description on product archives. + */ + function woocommerce_product_archive_description() { + // Don't display the description on search results page. + if ( is_search() ) { + return; + } + + if ( is_post_type_archive( 'product' ) && in_array( absint( get_query_var( 'paged' ) ), array( 0, 1 ), true ) ) { + $shop_page = get_post( wc_get_page_id( 'shop' ) ); + if ( $shop_page ) { + $description = wc_format_content( $shop_page->post_content ); + if ( $description ) { + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo '
'; + } + } + } + } +} + +if ( ! function_exists( 'woocommerce_template_loop_add_to_cart' ) ) { + + /** + * Get the add to cart template for the loop. + * + * @param array $args Arguments. + */ + function woocommerce_template_loop_add_to_cart( $args = array() ) { + global $product; + + if ( $product ) { + $defaults = array( + 'quantity' => 1, + 'class' => implode( + ' ', + array_filter( + array( + 'button', + 'product_type_' . $product->get_type(), + $product->is_purchasable() && $product->is_in_stock() ? 'add_to_cart_button' : '', + $product->supports( 'ajax_add_to_cart' ) && $product->is_purchasable() && $product->is_in_stock() ? 'ajax_add_to_cart' : '', + ) + ) + ), + 'attributes' => array( + 'data-product_id' => $product->get_id(), + 'data-product_sku' => $product->get_sku(), + 'aria-label' => $product->add_to_cart_description(), + 'rel' => 'nofollow', + ), + ); + + $args = apply_filters( 'woocommerce_loop_add_to_cart_args', wp_parse_args( $args, $defaults ), $product ); + + if ( isset( $args['attributes']['aria-label'] ) ) { + $args['attributes']['aria-label'] = wp_strip_all_tags( $args['attributes']['aria-label'] ); + } + + wc_get_template( 'loop/add-to-cart.php', $args ); + } + } +} + +if ( ! function_exists( 'woocommerce_template_loop_product_thumbnail' ) ) { + + /** + * Get the product thumbnail for the loop. + */ + function woocommerce_template_loop_product_thumbnail() { + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo woocommerce_get_product_thumbnail(); + } +} +if ( ! function_exists( 'woocommerce_template_loop_price' ) ) { + + /** + * Get the product price for the loop. + */ + function woocommerce_template_loop_price() { + wc_get_template( 'loop/price.php' ); + } +} +if ( ! function_exists( 'woocommerce_template_loop_rating' ) ) { + + /** + * Display the average rating in the loop. + */ + function woocommerce_template_loop_rating() { + wc_get_template( 'loop/rating.php' ); + } +} +if ( ! function_exists( 'woocommerce_show_product_loop_sale_flash' ) ) { + + /** + * Get the sale flash for the loop. + */ + function woocommerce_show_product_loop_sale_flash() { + wc_get_template( 'loop/sale-flash.php' ); + } +} + +if ( ! function_exists( 'woocommerce_get_product_thumbnail' ) ) { + + /** + * Get the product thumbnail, or the placeholder if not set. + * + * @param string $size (default: 'woocommerce_thumbnail'). + * @param int $deprecated1 Deprecated since WooCommerce 2.0 (default: 0). + * @param int $deprecated2 Deprecated since WooCommerce 2.0 (default: 0). + * @return string + */ + function woocommerce_get_product_thumbnail( $size = 'woocommerce_thumbnail', $deprecated1 = 0, $deprecated2 = 0 ) { + global $product; + + $image_size = apply_filters( 'single_product_archive_thumbnail_size', $size ); + + return $product ? $product->get_image( $image_size ) : ''; + } +} + +if ( ! function_exists( 'woocommerce_result_count' ) ) { + + /** + * Output the result count text (Showing x - x of x results). + */ + function woocommerce_result_count() { + if ( ! wc_get_loop_prop( 'is_paginated' ) || ! woocommerce_products_will_display() ) { + return; + } + $args = array( + 'total' => wc_get_loop_prop( 'total' ), + 'per_page' => wc_get_loop_prop( 'per_page' ), + 'current' => wc_get_loop_prop( 'current_page' ), + ); + + wc_get_template( 'loop/result-count.php', $args ); + } +} + +if ( ! function_exists( 'woocommerce_catalog_ordering' ) ) { + + /** + * Output the product sorting options. + */ + function woocommerce_catalog_ordering() { + if ( ! wc_get_loop_prop( 'is_paginated' ) || ! woocommerce_products_will_display() ) { + return; + } + $show_default_orderby = 'menu_order' === apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby', 'menu_order' ) ); + $catalog_orderby_options = apply_filters( + 'woocommerce_catalog_orderby', + array( + 'menu_order' => __( 'Default sorting', 'woocommerce' ), + 'popularity' => __( 'Sort by popularity', 'woocommerce' ), + 'rating' => __( 'Sort by average rating', 'woocommerce' ), + 'date' => __( 'Sort by latest', 'woocommerce' ), + 'price' => __( 'Sort by price: low to high', 'woocommerce' ), + 'price-desc' => __( 'Sort by price: high to low', 'woocommerce' ), + ) + ); + + $default_orderby = wc_get_loop_prop( 'is_search' ) ? 'relevance' : apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby', '' ) ); + // phpcs:disable WordPress.Security.NonceVerification.Recommended + $orderby = isset( $_GET['orderby'] ) ? wc_clean( wp_unslash( $_GET['orderby'] ) ) : $default_orderby; + // phpcs:enable WordPress.Security.NonceVerification.Recommended + + if ( wc_get_loop_prop( 'is_search' ) ) { + $catalog_orderby_options = array_merge( array( 'relevance' => __( 'Relevance', 'woocommerce' ) ), $catalog_orderby_options ); + + unset( $catalog_orderby_options['menu_order'] ); + } + + if ( ! $show_default_orderby ) { + unset( $catalog_orderby_options['menu_order'] ); + } + + if ( ! wc_review_ratings_enabled() ) { + unset( $catalog_orderby_options['rating'] ); + } + + if ( ! array_key_exists( $orderby, $catalog_orderby_options ) ) { + $orderby = current( array_keys( $catalog_orderby_options ) ); + } + + wc_get_template( + 'loop/orderby.php', + array( + 'catalog_orderby_options' => $catalog_orderby_options, + 'orderby' => $orderby, + 'show_default_orderby' => $show_default_orderby, + ) + ); + } +} + +if ( ! function_exists( 'woocommerce_pagination' ) ) { + + /** + * Output the pagination. + */ + function woocommerce_pagination() { + if ( ! wc_get_loop_prop( 'is_paginated' ) || ! woocommerce_products_will_display() ) { + return; + } + + $args = array( + 'total' => wc_get_loop_prop( 'total_pages' ), + 'current' => wc_get_loop_prop( 'current_page' ), + 'base' => esc_url_raw( add_query_arg( 'product-page', '%#%', false ) ), + 'format' => '?product-page=%#%', + ); + + if ( ! wc_get_loop_prop( 'is_shortcode' ) ) { + $args['format'] = ''; + $args['base'] = esc_url_raw( str_replace( 999999999, '%#%', remove_query_arg( 'add-to-cart', get_pagenum_link( 999999999, false ) ) ) ); + } + + wc_get_template( 'loop/pagination.php', $args ); + } +} + +/** + * Single Product + */ + +if ( ! function_exists( 'woocommerce_show_product_images' ) ) { + + /** + * Output the product image before the single product summary. + */ + function woocommerce_show_product_images() { + wc_get_template( 'single-product/product-image.php' ); + } +} +if ( ! function_exists( 'woocommerce_show_product_thumbnails' ) ) { + + /** + * Output the product thumbnails. + */ + function woocommerce_show_product_thumbnails() { + wc_get_template( 'single-product/product-thumbnails.php' ); + } +} + +/** + * Get HTML for a gallery image. + * + * Hooks: woocommerce_gallery_thumbnail_size, woocommerce_gallery_image_size and woocommerce_gallery_full_size accept name based image sizes, or an array of width/height values. + * + * @since 3.3.2 + * @param int $attachment_id Attachment ID. + * @param bool $main_image Is this the main image or a thumbnail?. + * @return string + */ +function wc_get_gallery_image_html( $attachment_id, $main_image = false ) { + $flexslider = (bool) apply_filters( 'woocommerce_single_product_flexslider_enabled', get_theme_support( 'wc-product-gallery-slider' ) ); + $gallery_thumbnail = wc_get_image_size( 'gallery_thumbnail' ); + $thumbnail_size = apply_filters( 'woocommerce_gallery_thumbnail_size', array( $gallery_thumbnail['width'], $gallery_thumbnail['height'] ) ); + $image_size = apply_filters( 'woocommerce_gallery_image_size', $flexslider || $main_image ? 'woocommerce_single' : $thumbnail_size ); + $full_size = apply_filters( 'woocommerce_gallery_full_size', apply_filters( 'woocommerce_product_thumbnails_large_size', 'full' ) ); + $thumbnail_src = wp_get_attachment_image_src( $attachment_id, $thumbnail_size ); + $full_src = wp_get_attachment_image_src( $attachment_id, $full_size ); + $alt_text = trim( wp_strip_all_tags( get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ) ) ); + $image = wp_get_attachment_image( + $attachment_id, + $image_size, + false, + apply_filters( + 'woocommerce_gallery_image_html_attachment_image_params', + array( + 'title' => _wp_specialchars( get_post_field( 'post_title', $attachment_id ), ENT_QUOTES, 'UTF-8', true ), + 'data-caption' => _wp_specialchars( get_post_field( 'post_excerpt', $attachment_id ), ENT_QUOTES, 'UTF-8', true ), + 'data-src' => esc_url( $full_src[0] ), + 'data-large_image' => esc_url( $full_src[0] ), + 'data-large_image_width' => esc_attr( $full_src[1] ), + 'data-large_image_height' => esc_attr( $full_src[2] ), + 'class' => esc_attr( $main_image ? 'wp-post-image' : '' ), + ), + $attachment_id, + $image_size, + $main_image + ) + ); + + return '
'; +} + +if ( ! function_exists( 'woocommerce_output_product_data_tabs' ) ) { + + /** + * Output the product tabs. + */ + function woocommerce_output_product_data_tabs() { + wc_get_template( 'single-product/tabs/tabs.php' ); + } +} +if ( ! function_exists( 'woocommerce_template_single_title' ) ) { + + /** + * Output the product title. + */ + function woocommerce_template_single_title() { + wc_get_template( 'single-product/title.php' ); + } +} +if ( ! function_exists( 'woocommerce_template_single_rating' ) ) { + + /** + * Output the product rating. + */ + function woocommerce_template_single_rating() { + if ( post_type_supports( 'product', 'comments' ) ) { + wc_get_template( 'single-product/rating.php' ); + } + } +} +if ( ! function_exists( 'woocommerce_template_single_price' ) ) { + + /** + * Output the product price. + */ + function woocommerce_template_single_price() { + wc_get_template( 'single-product/price.php' ); + } +} +if ( ! function_exists( 'woocommerce_template_single_excerpt' ) ) { + + /** + * Output the product short description (excerpt). + */ + function woocommerce_template_single_excerpt() { + wc_get_template( 'single-product/short-description.php' ); + } +} +if ( ! function_exists( 'woocommerce_template_single_meta' ) ) { + + /** + * Output the product meta. + */ + function woocommerce_template_single_meta() { + wc_get_template( 'single-product/meta.php' ); + } +} +if ( ! function_exists( 'woocommerce_template_single_sharing' ) ) { + + /** + * Output the product sharing. + */ + function woocommerce_template_single_sharing() { + wc_get_template( 'single-product/share.php' ); + } +} +if ( ! function_exists( 'woocommerce_show_product_sale_flash' ) ) { + + /** + * Output the product sale flash. + */ + function woocommerce_show_product_sale_flash() { + wc_get_template( 'single-product/sale-flash.php' ); + } +} + +if ( ! function_exists( 'woocommerce_template_single_add_to_cart' ) ) { + + /** + * Trigger the single product add to cart action. + */ + function woocommerce_template_single_add_to_cart() { + global $product; + do_action( 'woocommerce_' . $product->get_type() . '_add_to_cart' ); + } +} +if ( ! function_exists( 'woocommerce_simple_add_to_cart' ) ) { + + /** + * Output the simple product add to cart area. + */ + function woocommerce_simple_add_to_cart() { + wc_get_template( 'single-product/add-to-cart/simple.php' ); + } +} +if ( ! function_exists( 'woocommerce_grouped_add_to_cart' ) ) { + + /** + * Output the grouped product add to cart area. + */ + function woocommerce_grouped_add_to_cart() { + global $product; + + $products = array_filter( array_map( 'wc_get_product', $product->get_children() ), 'wc_products_array_filter_visible_grouped' ); + + if ( $products ) { + wc_get_template( + 'single-product/add-to-cart/grouped.php', + array( + 'grouped_product' => $product, + 'grouped_products' => $products, + 'quantites_required' => false, + ) + ); + } + } +} +if ( ! function_exists( 'woocommerce_variable_add_to_cart' ) ) { + + /** + * Output the variable product add to cart area. + */ + function woocommerce_variable_add_to_cart() { + global $product; + + // Enqueue variation scripts. + wp_enqueue_script( 'wc-add-to-cart-variation' ); + + // Get Available variations? + $get_variations = count( $product->get_children() ) <= apply_filters( 'woocommerce_ajax_variation_threshold', 30, $product ); + + // Load the template. + wc_get_template( + 'single-product/add-to-cart/variable.php', + array( + 'available_variations' => $get_variations ? $product->get_available_variations() : false, + 'attributes' => $product->get_variation_attributes(), + 'selected_attributes' => $product->get_default_attributes(), + ) + ); + } +} +if ( ! function_exists( 'woocommerce_external_add_to_cart' ) ) { + + /** + * Output the external product add to cart area. + */ + function woocommerce_external_add_to_cart() { + global $product; + + if ( ! $product->add_to_cart_url() ) { + return; + } + + wc_get_template( + 'single-product/add-to-cart/external.php', + array( + 'product_url' => $product->add_to_cart_url(), + 'button_text' => $product->single_add_to_cart_text(), + ) + ); + } +} + +if ( ! function_exists( 'woocommerce_quantity_input' ) ) { + + /** + * Output the quantity input for add to cart forms. + * + * @param array $args Args for the input. + * @param WC_Product|null $product Product. + * @param boolean $echo Whether to return or echo|string. + * + * @return string + */ + function woocommerce_quantity_input( $args = array(), $product = null, $echo = true ) { + if ( is_null( $product ) ) { + $product = $GLOBALS['product']; + } + + $defaults = array( + 'input_id' => uniqid( 'quantity_' ), + 'input_name' => 'quantity', + 'input_value' => '1', + 'classes' => apply_filters( 'woocommerce_quantity_input_classes', array( 'input-text', 'qty', 'text' ), $product ), + 'max_value' => apply_filters( 'woocommerce_quantity_input_max', -1, $product ), + 'min_value' => apply_filters( 'woocommerce_quantity_input_min', 0, $product ), + 'step' => apply_filters( 'woocommerce_quantity_input_step', 1, $product ), + 'pattern' => apply_filters( 'woocommerce_quantity_input_pattern', has_filter( 'woocommerce_stock_amount', 'intval' ) ? '[0-9]*' : '' ), + 'inputmode' => apply_filters( 'woocommerce_quantity_input_inputmode', has_filter( 'woocommerce_stock_amount', 'intval' ) ? 'numeric' : '' ), + 'product_name' => $product ? $product->get_title() : '', + 'placeholder' => apply_filters( 'woocommerce_quantity_input_placeholder', '', $product ), + ); + + $args = apply_filters( 'woocommerce_quantity_input_args', wp_parse_args( $args, $defaults ), $product ); + + // Apply sanity to min/max args - min cannot be lower than 0. + $args['min_value'] = max( $args['min_value'], 0 ); + $args['max_value'] = 0 < $args['max_value'] ? $args['max_value'] : ''; + + // Max cannot be lower than min if defined. + if ( '' !== $args['max_value'] && $args['max_value'] < $args['min_value'] ) { + $args['max_value'] = $args['min_value']; + } + + ob_start(); + + wc_get_template( 'global/quantity-input.php', $args ); + + if ( $echo ) { + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo ob_get_clean(); + } else { + return ob_get_clean(); + } + } +} + +if ( ! function_exists( 'woocommerce_product_description_tab' ) ) { + + /** + * Output the description tab content. + */ + function woocommerce_product_description_tab() { + wc_get_template( 'single-product/tabs/description.php' ); + } +} +if ( ! function_exists( 'woocommerce_product_additional_information_tab' ) ) { + + /** + * Output the attributes tab content. + */ + function woocommerce_product_additional_information_tab() { + wc_get_template( 'single-product/tabs/additional-information.php' ); + } +} +if ( ! function_exists( 'woocommerce_default_product_tabs' ) ) { + + /** + * Add default product tabs to product pages. + * + * @param array $tabs Array of tabs. + * @return array + */ + function woocommerce_default_product_tabs( $tabs = array() ) { + global $product, $post; + + // Description tab - shows product content. + if ( $post->post_content ) { + $tabs['description'] = array( + 'title' => __( 'Description', 'woocommerce' ), + 'priority' => 10, + 'callback' => 'woocommerce_product_description_tab', + ); + } + + // Additional information tab - shows attributes. + if ( $product && ( $product->has_attributes() || apply_filters( 'wc_product_enable_dimensions_display', $product->has_weight() || $product->has_dimensions() ) ) ) { + $tabs['additional_information'] = array( + 'title' => __( 'Additional information', 'woocommerce' ), + 'priority' => 20, + 'callback' => 'woocommerce_product_additional_information_tab', + ); + } + + // Reviews tab - shows comments. + if ( comments_open() ) { + $tabs['reviews'] = array( + /* translators: %s: reviews count */ + 'title' => sprintf( __( 'Reviews (%d)', 'woocommerce' ), $product->get_review_count() ), + 'priority' => 30, + 'callback' => 'comments_template', + ); + } + + return $tabs; + } +} + +if ( ! function_exists( 'woocommerce_sort_product_tabs' ) ) { + + /** + * Sort tabs by priority. + * + * @param array $tabs Array of tabs. + * @return array + */ + function woocommerce_sort_product_tabs( $tabs = array() ) { + + // Make sure the $tabs parameter is an array. + if ( ! is_array( $tabs ) ) { + // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error + trigger_error( 'Function woocommerce_sort_product_tabs() expects an array as the first parameter. Defaulting to empty array.' ); + $tabs = array(); + } + + // Re-order tabs by priority. + if ( ! function_exists( '_sort_priority_callback' ) ) { + /** + * Sort Priority Callback Function + * + * @param array $a Comparison A. + * @param array $b Comparison B. + * @return bool + */ + function _sort_priority_callback( $a, $b ) { + if ( ! isset( $a['priority'], $b['priority'] ) || $a['priority'] === $b['priority'] ) { + return 0; + } + return ( $a['priority'] < $b['priority'] ) ? -1 : 1; + } + } + + uasort( $tabs, '_sort_priority_callback' ); + + return $tabs; + } +} + +if ( ! function_exists( 'woocommerce_comments' ) ) { + + /** + * Output the Review comments template. + * + * @param WP_Comment $comment Comment object. + * @param array $args Arguments. + * @param int $depth Depth. + */ + function woocommerce_comments( $comment, $args, $depth ) { + // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited + $GLOBALS['comment'] = $comment; + wc_get_template( + 'single-product/review.php', + array( + 'comment' => $comment, + 'args' => $args, + 'depth' => $depth, + ) + ); + } +} + +if ( ! function_exists( 'woocommerce_review_display_gravatar' ) ) { + /** + * Display the review authors gravatar + * + * @param array $comment WP_Comment. + * @return void + */ + function woocommerce_review_display_gravatar( $comment ) { + echo get_avatar( $comment, apply_filters( 'woocommerce_review_gravatar_size', '60' ), '' ); + } +} + +if ( ! function_exists( 'woocommerce_review_display_rating' ) ) { + /** + * Display the reviewers star rating + * + * @return void + */ + function woocommerce_review_display_rating() { + if ( post_type_supports( 'product', 'comments' ) ) { + wc_get_template( 'single-product/review-rating.php' ); + } + } +} + +if ( ! function_exists( 'woocommerce_review_display_meta' ) ) { + /** + * Display the review authors meta (name, verified owner, review date) + * + * @return void + */ + function woocommerce_review_display_meta() { + wc_get_template( 'single-product/review-meta.php' ); + } +} + +if ( ! function_exists( 'woocommerce_review_display_comment_text' ) ) { + + /** + * Display the review content. + */ + function woocommerce_review_display_comment_text() { + echo '
';
+ }
+}
+
+if ( ! function_exists( 'woocommerce_output_related_products' ) ) {
+
+ /**
+ * Output the related products.
+ */
+ function woocommerce_output_related_products() {
+
+ $args = array(
+ 'posts_per_page' => 4,
+ 'columns' => 4,
+ 'orderby' => 'rand', // @codingStandardsIgnoreLine.
+ );
+
+ woocommerce_related_products( apply_filters( 'woocommerce_output_related_products_args', $args ) );
+ }
+}
+
+if ( ! function_exists( 'woocommerce_related_products' ) ) {
+
+ /**
+ * Output the related products.
+ *
+ * @param array $args Provided arguments.
+ */
+ function woocommerce_related_products( $args = array() ) {
+ global $product;
+
+ if ( ! $product ) {
+ return;
+ }
+
+ $defaults = array(
+ 'posts_per_page' => 2,
+ 'columns' => 2,
+ 'orderby' => 'rand', // @codingStandardsIgnoreLine.
+ 'order' => 'desc',
+ );
+
+ $args = wp_parse_args( $args, $defaults );
+
+ // Get visible related products then sort them at random.
+ $args['related_products'] = array_filter( array_map( 'wc_get_product', wc_get_related_products( $product->get_id(), $args['posts_per_page'], $product->get_upsell_ids() ) ), 'wc_products_array_filter_visible' );
+
+ // Handle orderby.
+ $args['related_products'] = wc_products_array_orderby( $args['related_products'], $args['orderby'], $args['order'] );
+
+ // Set global loop values.
+ wc_set_loop_prop( 'name', 'related' );
+ wc_set_loop_prop( 'columns', apply_filters( 'woocommerce_related_products_columns', $args['columns'] ) );
+
+ wc_get_template( 'single-product/related.php', $args );
+ }
+}
+
+if ( ! function_exists( 'woocommerce_upsell_display' ) ) {
+
+ /**
+ * Output product up sells.
+ *
+ * @param int $limit (default: -1).
+ * @param int $columns (default: 4).
+ * @param string $orderby Supported values - rand, title, ID, date, modified, menu_order, price.
+ * @param string $order Sort direction.
+ */
+ function woocommerce_upsell_display( $limit = '-1', $columns = 4, $orderby = 'rand', $order = 'desc' ) {
+ global $product;
+
+ if ( ! $product ) {
+ return;
+ }
+
+ // Handle the legacy filter which controlled posts per page etc.
+ $args = apply_filters(
+ 'woocommerce_upsell_display_args',
+ array(
+ 'posts_per_page' => $limit,
+ 'orderby' => $orderby,
+ 'order' => $order,
+ 'columns' => $columns,
+ )
+ );
+ wc_set_loop_prop( 'name', 'up-sells' );
+ wc_set_loop_prop( 'columns', apply_filters( 'woocommerce_upsells_columns', isset( $args['columns'] ) ? $args['columns'] : $columns ) );
+
+ $orderby = apply_filters( 'woocommerce_upsells_orderby', isset( $args['orderby'] ) ? $args['orderby'] : $orderby );
+ $order = apply_filters( 'woocommerce_upsells_order', isset( $args['order'] ) ? $args['order'] : $order );
+ $limit = apply_filters( 'woocommerce_upsells_total', isset( $args['posts_per_page'] ) ? $args['posts_per_page'] : $limit );
+
+ // Get visible upsells then sort them at random, then limit result set.
+ $upsells = wc_products_array_orderby( array_filter( array_map( 'wc_get_product', $product->get_upsell_ids() ), 'wc_products_array_filter_visible' ), $orderby, $order );
+ $upsells = $limit > 0 ? array_slice( $upsells, 0, $limit ) : $upsells;
+
+ wc_get_template(
+ 'single-product/up-sells.php',
+ array(
+ 'upsells' => $upsells,
+
+ // Not used now, but used in previous version of up-sells.php.
+ 'posts_per_page' => $limit,
+ 'orderby' => $orderby,
+ 'columns' => $columns,
+ )
+ );
+ }
+}
+
+/** Cart */
+
+if ( ! function_exists( 'woocommerce_shipping_calculator' ) ) {
+
+ /**
+ * Output the cart shipping calculator.
+ *
+ * @param string $button_text Text for the shipping calculation toggle.
+ */
+ function woocommerce_shipping_calculator( $button_text = '' ) {
+ if ( 'no' === get_option( 'woocommerce_enable_shipping_calc' ) || ! WC()->cart->needs_shipping() ) {
+ return;
+ }
+ wp_enqueue_script( 'wc-country-select' );
+ wc_get_template(
+ 'cart/shipping-calculator.php',
+ array(
+ 'button_text' => $button_text,
+ )
+ );
+ }
+}
+
+if ( ! function_exists( 'woocommerce_cart_totals' ) ) {
+
+ /**
+ * Output the cart totals.
+ */
+ function woocommerce_cart_totals() {
+ if ( is_checkout() ) {
+ return;
+ }
+ wc_get_template( 'cart/cart-totals.php' );
+ }
+}
+
+if ( ! function_exists( 'woocommerce_cross_sell_display' ) ) {
+
+ /**
+ * Output the cart cross-sells.
+ *
+ * @param int $limit (default: 2).
+ * @param int $columns (default: 2).
+ * @param string $orderby (default: 'rand').
+ * @param string $order (default: 'desc').
+ */
+ function woocommerce_cross_sell_display( $limit = 2, $columns = 2, $orderby = 'rand', $order = 'desc' ) {
+ if ( is_checkout() ) {
+ return;
+ }
+ // Get visible cross sells then sort them at random.
+ $cross_sells = array_filter( array_map( 'wc_get_product', WC()->cart->get_cross_sells() ), 'wc_products_array_filter_visible' );
+
+ wc_set_loop_prop( 'name', 'cross-sells' );
+ wc_set_loop_prop( 'columns', apply_filters( 'woocommerce_cross_sells_columns', $columns ) );
+
+ // Handle orderby and limit results.
+ $orderby = apply_filters( 'woocommerce_cross_sells_orderby', $orderby );
+ $order = apply_filters( 'woocommerce_cross_sells_order', $order );
+ $cross_sells = wc_products_array_orderby( $cross_sells, $orderby, $order );
+ $limit = apply_filters( 'woocommerce_cross_sells_total', $limit );
+ $cross_sells = $limit > 0 ? array_slice( $cross_sells, 0, $limit ) : $cross_sells;
+
+ wc_get_template(
+ 'cart/cross-sells.php',
+ array(
+ 'cross_sells' => $cross_sells,
+
+ // Not used now, but used in previous version of up-sells.php.
+ 'posts_per_page' => $limit,
+ 'orderby' => $orderby,
+ 'columns' => $columns,
+ )
+ );
+ }
+}
+
+if ( ! function_exists( 'woocommerce_button_proceed_to_checkout' ) ) {
+
+ /**
+ * Output the proceed to checkout button.
+ */
+ function woocommerce_button_proceed_to_checkout() {
+ wc_get_template( 'cart/proceed-to-checkout-button.php' );
+ }
+}
+
+if ( ! function_exists( 'woocommerce_widget_shopping_cart_button_view_cart' ) ) {
+
+ /**
+ * Output the view cart button.
+ */
+ function woocommerce_widget_shopping_cart_button_view_cart() {
+ echo '' . esc_html__( 'View cart', 'woocommerce' ) . '';
+ }
+}
+
+if ( ! function_exists( 'woocommerce_widget_shopping_cart_proceed_to_checkout' ) ) {
+
+ /**
+ * Output the proceed to checkout button.
+ */
+ function woocommerce_widget_shopping_cart_proceed_to_checkout() {
+ echo '' . esc_html__( 'Checkout', 'woocommerce' ) . '';
+ }
+}
+
+if ( ! function_exists( 'woocommerce_widget_shopping_cart_subtotal' ) ) {
+ /**
+ * Output to view cart subtotal.
+ *
+ * @since 3.7.0
+ */
+ function woocommerce_widget_shopping_cart_subtotal() {
+ echo '' . esc_html__( 'Subtotal:', 'woocommerce' ) . ' ' . WC()->cart->get_cart_subtotal(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ }
+}
+
+/** Mini-Cart */
+
+if ( ! function_exists( 'woocommerce_mini_cart' ) ) {
+
+ /**
+ * Output the Mini-cart - used by cart widget.
+ *
+ * @param array $args Arguments.
+ */
+ function woocommerce_mini_cart( $args = array() ) {
+
+ $defaults = array(
+ 'list_class' => '',
+ );
+
+ $args = wp_parse_args( $args, $defaults );
+
+ wc_get_template( 'cart/mini-cart.php', $args );
+ }
+}
+
+/** Login */
+
+if ( ! function_exists( 'woocommerce_login_form' ) ) {
+
+ /**
+ * Output the WooCommerce Login Form.
+ *
+ * @param array $args Arguments.
+ */
+ function woocommerce_login_form( $args = array() ) {
+
+ $defaults = array(
+ 'message' => '',
+ 'redirect' => '',
+ 'hidden' => false,
+ );
+
+ $args = wp_parse_args( $args, $defaults );
+
+ wc_get_template( 'global/form-login.php', $args );
+ }
+}
+
+if ( ! function_exists( 'woocommerce_checkout_login_form' ) ) {
+
+ /**
+ * Output the WooCommerce Checkout Login Form.
+ */
+ function woocommerce_checkout_login_form() {
+ wc_get_template(
+ 'checkout/form-login.php',
+ array(
+ 'checkout' => WC()->checkout(),
+ )
+ );
+ }
+}
+
+if ( ! function_exists( 'woocommerce_breadcrumb' ) ) {
+
+ /**
+ * Output the WooCommerce Breadcrumb.
+ *
+ * @param array $args Arguments.
+ */
+ function woocommerce_breadcrumb( $args = array() ) {
+ $args = wp_parse_args(
+ $args,
+ apply_filters(
+ 'woocommerce_breadcrumb_defaults',
+ array(
+ 'delimiter' => ' / ',
+ 'wrap_before' => '',
+ 'before' => '',
+ 'after' => '',
+ 'home' => _x( 'Home', 'breadcrumb', 'woocommerce' ),
+ )
+ )
+ );
+
+ $breadcrumbs = new WC_Breadcrumb();
+
+ if ( ! empty( $args['home'] ) ) {
+ $breadcrumbs->add_crumb( $args['home'], apply_filters( 'woocommerce_breadcrumb_home_url', home_url() ) );
+ }
+
+ $args['breadcrumb'] = $breadcrumbs->generate();
+
+ /**
+ * WooCommerce Breadcrumb hook
+ *
+ * @hooked WC_Structured_Data::generate_breadcrumblist_data() - 10
+ */
+ do_action( 'woocommerce_breadcrumb', $breadcrumbs, $args );
+
+ wc_get_template( 'global/breadcrumb.php', $args );
+ }
+}
+
+if ( ! function_exists( 'woocommerce_order_review' ) ) {
+
+ /**
+ * Output the Order review table for the checkout.
+ *
+ * @param bool $deprecated Deprecated param.
+ */
+ function woocommerce_order_review( $deprecated = false ) {
+ wc_get_template(
+ 'checkout/review-order.php',
+ array(
+ 'checkout' => WC()->checkout(),
+ )
+ );
+ }
+}
+
+if ( ! function_exists( 'woocommerce_checkout_payment' ) ) {
+
+ /**
+ * Output the Payment Methods on the checkout.
+ */
+ function woocommerce_checkout_payment() {
+ if ( WC()->cart->needs_payment() ) {
+ $available_gateways = WC()->payment_gateways()->get_available_payment_gateways();
+ WC()->payment_gateways()->set_current_gateway( $available_gateways );
+ } else {
+ $available_gateways = array();
+ }
+
+ wc_get_template(
+ 'checkout/payment.php',
+ array(
+ 'checkout' => WC()->checkout(),
+ 'available_gateways' => $available_gateways,
+ 'order_button_text' => apply_filters( 'woocommerce_order_button_text', __( 'Place order', 'woocommerce' ) ),
+ )
+ );
+ }
+}
+
+if ( ! function_exists( 'woocommerce_checkout_coupon_form' ) ) {
+
+ /**
+ * Output the Coupon form for the checkout.
+ */
+ function woocommerce_checkout_coupon_form() {
+ wc_get_template(
+ 'checkout/form-coupon.php',
+ array(
+ 'checkout' => WC()->checkout(),
+ )
+ );
+ }
+}
+
+if ( ! function_exists( 'woocommerce_products_will_display' ) ) {
+
+ /**
+ * Check if we will be showing products or not (and not sub-categories only).
+ *
+ * @return bool
+ */
+ function woocommerce_products_will_display() {
+ $display_type = woocommerce_get_loop_display_mode();
+
+ return 0 < wc_get_loop_prop( 'total', 0 ) && 'subcategories' !== $display_type;
+ }
+}
+
+if ( ! function_exists( 'woocommerce_get_loop_display_mode' ) ) {
+
+ /**
+ * See what is going to display in the loop.
+ *
+ * @since 3.3.0
+ * @return string Either products, subcategories, or both, based on current page.
+ */
+ function woocommerce_get_loop_display_mode() {
+ // Only return products when filtering things.
+ if ( wc_get_loop_prop( 'is_search' ) || wc_get_loop_prop( 'is_filtered' ) ) {
+ return 'products';
+ }
+
+ $parent_id = 0;
+ $display_type = '';
+
+ if ( is_shop() ) {
+ $display_type = get_option( 'woocommerce_shop_page_display', '' );
+ } elseif ( is_product_category() ) {
+ $parent_id = get_queried_object_id();
+ $display_type = get_term_meta( $parent_id, 'display_type', true );
+ $display_type = '' === $display_type ? get_option( 'woocommerce_category_archive_display', '' ) : $display_type;
+ }
+
+ if ( ( ! is_shop() || 'subcategories' !== $display_type ) && 1 < wc_get_loop_prop( 'current_page' ) ) {
+ return 'products';
+ }
+
+ // Ensure valid value.
+ if ( '' === $display_type || ! in_array( $display_type, array( 'products', 'subcategories', 'both' ), true ) ) {
+ $display_type = 'products';
+ }
+
+ // If we're showing categories, ensure we actually have something to show.
+ if ( in_array( $display_type, array( 'subcategories', 'both' ), true ) ) {
+ $subcategories = woocommerce_get_product_subcategories( $parent_id );
+
+ if ( empty( $subcategories ) ) {
+ $display_type = 'products';
+ }
+ }
+
+ return $display_type;
+ }
+}
+
+if ( ! function_exists( 'woocommerce_maybe_show_product_subcategories' ) ) {
+
+ /**
+ * Maybe display categories before, or instead of, a product loop.
+ *
+ * @since 3.3.0
+ * @param string $loop_html HTML.
+ * @return string
+ */
+ function woocommerce_maybe_show_product_subcategories( $loop_html = '' ) {
+ if ( wc_get_loop_prop( 'is_shortcode' ) && ! WC_Template_Loader::in_content_filter() ) {
+ return $loop_html;
+ }
+
+ $display_type = woocommerce_get_loop_display_mode();
+
+ // If displaying categories, append to the loop.
+ if ( 'subcategories' === $display_type || 'both' === $display_type ) {
+ ob_start();
+ woocommerce_output_product_categories(
+ array(
+ 'parent_id' => is_product_category() ? get_queried_object_id() : 0,
+ )
+ );
+ $loop_html .= ob_get_clean();
+
+ if ( 'subcategories' === $display_type ) {
+ wc_set_loop_prop( 'total', 0 );
+
+ // This removes pagination and products from display for themes not using wc_get_loop_prop in their product loops. @todo Remove in future major version.
+ global $wp_query;
+
+ if ( $wp_query->is_main_query() ) {
+ $wp_query->post_count = 0;
+ $wp_query->max_num_pages = 0;
+ }
+ }
+ }
+
+ return $loop_html;
+ }
+}
+
+if ( ! function_exists( 'woocommerce_product_subcategories' ) ) {
+ /**
+ * This is a legacy function which used to check if we needed to display subcats and then output them. It was called by templates.
+ *
+ * From 3.3 onwards this is all handled via hooks and the woocommerce_maybe_show_product_subcategories function.
+ *
+ * Since some templates have not updated compatibility, to avoid showing incorrect categories this function has been deprecated and will
+ * return nothing. Replace usage with woocommerce_output_product_categories to render the category list manually.
+ *
+ * This is a legacy function which also checks if things should display.
+ * Themes no longer need to call these functions. It's all done via hooks.
+ *
+ * @deprecated 3.3.1 @todo Add a notice in a future version.
+ * @param array $args Arguments.
+ * @return null|boolean
+ */
+ function woocommerce_product_subcategories( $args = array() ) {
+ $defaults = array(
+ 'before' => '',
+ 'after' => '',
+ 'force_display' => false,
+ );
+
+ $args = wp_parse_args( $args, $defaults );
+
+ if ( $args['force_display'] ) {
+ // We can still render if display is forced.
+ woocommerce_output_product_categories(
+ array(
+ 'before' => $args['before'],
+ 'after' => $args['after'],
+ 'parent_id' => is_product_category() ? get_queried_object_id() : 0,
+ )
+ );
+ return true;
+ } else {
+ // Output nothing. woocommerce_maybe_show_product_subcategories will handle the output of cats.
+ $display_type = woocommerce_get_loop_display_mode();
+
+ if ( 'subcategories' === $display_type ) {
+ // This removes pagination and products from display for themes not using wc_get_loop_prop in their product loops. @todo Remove in future major version.
+ global $wp_query;
+
+ if ( $wp_query->is_main_query() ) {
+ $wp_query->post_count = 0;
+ $wp_query->max_num_pages = 0;
+ }
+ }
+
+ return 'subcategories' === $display_type || 'both' === $display_type;
+ }
+ }
+}
+
+if ( ! function_exists( 'woocommerce_output_product_categories' ) ) {
+ /**
+ * Display product sub categories as thumbnails.
+ *
+ * This is a replacement for woocommerce_product_subcategories which also does some logic
+ * based on the loop. This function however just outputs when called.
+ *
+ * @since 3.3.1
+ * @param array $args Arguments.
+ * @return boolean
+ */
+ function woocommerce_output_product_categories( $args = array() ) {
+ $args = wp_parse_args(
+ $args,
+ array(
+ 'before' => apply_filters( 'woocommerce_before_output_product_categories', '' ),
+ 'after' => apply_filters( 'woocommerce_after_output_product_categories', '' ),
+ 'parent_id' => 0,
+ )
+ );
+
+ $product_categories = woocommerce_get_product_subcategories( $args['parent_id'] );
+
+ if ( ! $product_categories ) {
+ return false;
+ }
+
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ echo $args['before'];
+
+ foreach ( $product_categories as $category ) {
+ wc_get_template(
+ 'content-product_cat.php',
+ array(
+ 'category' => $category,
+ )
+ );
+ }
+
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ echo $args['after'];
+
+ return true;
+ }
+}
+
+if ( ! function_exists( 'woocommerce_get_product_subcategories' ) ) {
+ /**
+ * Get (and cache) product subcategories.
+ *
+ * @param int $parent_id Get subcategories of this ID.
+ * @return array
+ */
+ function woocommerce_get_product_subcategories( $parent_id = 0 ) {
+ $parent_id = absint( $parent_id );
+ $cache_key = apply_filters( 'woocommerce_get_product_subcategories_cache_key', 'product-category-hierarchy-' . $parent_id, $parent_id );
+ $product_categories = $cache_key ? wp_cache_get( $cache_key, 'product_cat' ) : false;
+
+ if ( false === $product_categories ) {
+ // NOTE: using child_of instead of parent - this is not ideal but due to a WP bug ( https://core.trac.wordpress.org/ticket/15626 ) pad_counts won't work.
+ $product_categories = get_categories(
+ apply_filters(
+ 'woocommerce_product_subcategories_args',
+ array(
+ 'parent' => $parent_id,
+ 'hide_empty' => 0,
+ 'hierarchical' => 1,
+ 'taxonomy' => 'product_cat',
+ 'pad_counts' => 1,
+ )
+ )
+ );
+
+ if ( $cache_key ) {
+ wp_cache_set( $cache_key, $product_categories, 'product_cat' );
+ }
+ }
+
+ if ( apply_filters( 'woocommerce_product_subcategories_hide_empty', true ) ) {
+ $product_categories = wp_list_filter( $product_categories, array( 'count' => 0 ), 'NOT' );
+ }
+
+ return $product_categories;
+ }
+}
+
+if ( ! function_exists( 'woocommerce_subcategory_thumbnail' ) ) {
+
+ /**
+ * Show subcategory thumbnails.
+ *
+ * @param mixed $category Category.
+ */
+ function woocommerce_subcategory_thumbnail( $category ) {
+ $small_thumbnail_size = apply_filters( 'subcategory_archive_thumbnail_size', 'woocommerce_thumbnail' );
+ $dimensions = wc_get_image_size( $small_thumbnail_size );
+ $thumbnail_id = get_term_meta( $category->term_id, 'thumbnail_id', true );
+
+ if ( $thumbnail_id ) {
+ $image = wp_get_attachment_image_src( $thumbnail_id, $small_thumbnail_size );
+ $image = $image[0];
+ $image_srcset = function_exists( 'wp_get_attachment_image_srcset' ) ? wp_get_attachment_image_srcset( $thumbnail_id, $small_thumbnail_size ) : false;
+ $image_sizes = function_exists( 'wp_get_attachment_image_sizes' ) ? wp_get_attachment_image_sizes( $thumbnail_id, $small_thumbnail_size ) : false;
+ } else {
+ $image = wc_placeholder_img_src();
+ $image_srcset = false;
+ $image_sizes = false;
+ }
+
+ if ( $image ) {
+ // Prevent esc_url from breaking spaces in urls for image embeds.
+ // Ref: https://core.trac.wordpress.org/ticket/23605.
+ $image = str_replace( ' ', '%20', $image );
+
+ // Add responsive image markup if available.
+ if ( $image_srcset && $image_sizes ) {
+ echo '';
+ } else {
+ echo '
';
+ }
+ }
+ }
+}
+
+if ( ! function_exists( 'woocommerce_order_details_table' ) ) {
+
+ /**
+ * Displays order details in a table.
+ *
+ * @param mixed $order_id Order ID.
+ */
+ function woocommerce_order_details_table( $order_id ) {
+ if ( ! $order_id ) {
+ return;
+ }
+
+ wc_get_template(
+ 'order/order-details.php',
+ array(
+ 'order_id' => $order_id,
+ )
+ );
+ }
+}
+
+if ( ! function_exists( 'woocommerce_order_downloads_table' ) ) {
+
+ /**
+ * Displays order downloads in a table.
+ *
+ * @since 3.2.0
+ * @param array $downloads Downloads.
+ */
+ function woocommerce_order_downloads_table( $downloads ) {
+ if ( ! $downloads ) {
+ return;
+ }
+ wc_get_template(
+ 'order/order-downloads.php',
+ array(
+ 'downloads' => $downloads,
+ )
+ );
+ }
+}
+
+if ( ! function_exists( 'woocommerce_order_again_button' ) ) {
+
+ /**
+ * Display an 'order again' button on the view order page.
+ *
+ * @param object $order Order.
+ */
+ function woocommerce_order_again_button( $order ) {
+ if ( ! $order || ! $order->has_status( apply_filters( 'woocommerce_valid_order_statuses_for_order_again', array( 'completed' ) ) ) || ! is_user_logged_in() ) {
+ return;
+ }
+
+ wc_get_template(
+ 'order/order-again.php',
+ array(
+ 'order' => $order,
+ 'order_again_url' => wp_nonce_url( add_query_arg( 'order_again', $order->get_id(), wc_get_cart_url() ), 'woocommerce-order_again' ),
+ )
+ );
+ }
+}
+
+/** Forms */
+
+if ( ! function_exists( 'woocommerce_form_field' ) ) {
+
+ /**
+ * Outputs a checkout/address form field.
+ *
+ * @param string $key Key.
+ * @param mixed $args Arguments.
+ * @param string $value (default: null).
+ * @return string
+ */
+ function woocommerce_form_field( $key, $args, $value = null ) {
+ $defaults = array(
+ 'type' => 'text',
+ 'label' => '',
+ 'description' => '',
+ 'placeholder' => '',
+ 'maxlength' => false,
+ 'required' => false,
+ 'autocomplete' => false,
+ 'id' => $key,
+ 'class' => array(),
+ 'label_class' => array(),
+ 'input_class' => array(),
+ 'return' => false,
+ 'options' => array(),
+ 'custom_attributes' => array(),
+ 'validate' => array(),
+ 'default' => '',
+ 'autofocus' => '',
+ 'priority' => '',
+ );
+
+ $args = wp_parse_args( $args, $defaults );
+ $args = apply_filters( 'woocommerce_form_field_args', $args, $key, $value );
+
+ if ( $args['required'] ) {
+ $args['class'][] = 'validate-required';
+ $required = ' *';
+ } else {
+ $required = ' (' . esc_html__( 'optional', 'woocommerce' ) . ')';
+ }
+
+ if ( is_string( $args['label_class'] ) ) {
+ $args['label_class'] = array( $args['label_class'] );
+ }
+
+ if ( is_null( $value ) ) {
+ $value = $args['default'];
+ }
+
+ // Custom attribute handling.
+ $custom_attributes = array();
+ $args['custom_attributes'] = array_filter( (array) $args['custom_attributes'], 'strlen' );
+
+ if ( $args['maxlength'] ) {
+ $args['custom_attributes']['maxlength'] = absint( $args['maxlength'] );
+ }
+
+ if ( ! empty( $args['autocomplete'] ) ) {
+ $args['custom_attributes']['autocomplete'] = $args['autocomplete'];
+ }
+
+ if ( true === $args['autofocus'] ) {
+ $args['custom_attributes']['autofocus'] = 'autofocus';
+ }
+
+ if ( $args['description'] ) {
+ $args['custom_attributes']['aria-describedby'] = $args['id'] . '-description';
+ }
+
+ if ( ! empty( $args['custom_attributes'] ) && is_array( $args['custom_attributes'] ) ) {
+ foreach ( $args['custom_attributes'] as $attribute => $attribute_value ) {
+ $custom_attributes[] = esc_attr( $attribute ) . '="' . esc_attr( $attribute_value ) . '"';
+ }
+ }
+
+ if ( ! empty( $args['validate'] ) ) {
+ foreach ( $args['validate'] as $validate ) {
+ $args['class'][] = 'validate-' . $validate;
+ }
+ }
+
+ $field = '';
+ $label_id = $args['id'];
+ $sort = $args['priority'] ? $args['priority'] : '';
+ $field_container = '
%3$s
'; + + switch ( $args['type'] ) { + case 'country': + $countries = 'shipping_country' === $key ? WC()->countries->get_shipping_countries() : WC()->countries->get_allowed_countries(); + + if ( 1 === count( $countries ) ) { + + $field .= '' . current( array_values( $countries ) ) . ''; + + $field .= ''; + + } else { + + $field = ''; + + $field .= ''; + + } + + break; + case 'state': + /* Get country this state field is representing */ + $for_country = isset( $args['country'] ) ? $args['country'] : WC()->checkout->get_value( 'billing_state' === $key ? 'billing_country' : 'shipping_country' ); + $states = WC()->countries->get_states( $for_country ); + + if ( is_array( $states ) && empty( $states ) ) { + + $field_container = '
'; + + $field .= ''; + + } elseif ( ! is_null( $for_country ) && is_array( $states ) ) { + + $field .= ''; + + } else { + + $field .= ''; + + } + + break; + case 'textarea': + $field .= ''; + + break; + case 'checkbox': + $field = ''; + + break; + case 'text': + case 'password': + case 'datetime': + case 'datetime-local': + case 'date': + case 'month': + case 'time': + case 'week': + case 'number': + case 'email': + case 'url': + case 'tel': + $field .= ''; + + break; + case 'hidden': + $field .= ''; + + break; + case 'select': + $field = ''; + $options = ''; + + if ( ! empty( $args['options'] ) ) { + foreach ( $args['options'] as $option_key => $option_text ) { + if ( '' === $option_key ) { + // If we have a blank option, select2 needs a placeholder. + if ( empty( $args['placeholder'] ) ) { + $args['placeholder'] = $option_text ? $option_text : __( 'Choose an option', 'woocommerce' ); + } + $custom_attributes[] = 'data-allow_clear="true"'; + } + $options .= ''; + } + + $field .= ''; + } + + break; + case 'radio': + $label_id .= '_' . current( array_keys( $args['options'] ) ); + + if ( ! empty( $args['options'] ) ) { + foreach ( $args['options'] as $option_key => $option_text ) { + $field .= ''; + $field .= ''; + } + } + + break; + } + + if ( ! empty( $field ) ) { + $field_html = ''; + + if ( $args['label'] && 'checkbox' !== $args['type'] ) { + $field_html .= ''; + } + + $field_html .= '' . $field; + + if ( $args['description'] ) { + $field_html .= ''; + + $container_class = esc_attr( implode( ' ', $args['class'] ) ); + $container_id = esc_attr( $args['id'] ) . '_field'; + $field = sprintf( $field_container, $container_class, $container_id, $field_html ); + } + + /** + * Filter by type. + */ + $field = apply_filters( 'woocommerce_form_field_' . $args['type'], $field, $key, $args, $value ); + + /** + * General filter on form fields. + * + * @since 3.4.0 + */ + $field = apply_filters( 'woocommerce_form_field', $field, $key, $args, $value ); + + if ( $args['return'] ) { + return $field; + } else { + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo $field; + } + } +} + +if ( ! function_exists( 'get_product_search_form' ) ) { + + /** + * Display product search form. + * + * Will first attempt to locate the product-searchform.php file in either the child or. + * the parent, then load it. If it doesn't exist, then the default search form. + * will be displayed. + * + * The default searchform uses html5. + * + * @param bool $echo (default: true). + * @return string + */ + function get_product_search_form( $echo = true ) { + global $product_search_form_index; + + ob_start(); + + if ( empty( $product_search_form_index ) ) { + $product_search_form_index = 0; + } + + do_action( 'pre_get_product_search_form' ); + + wc_get_template( + 'product-searchform.php', + array( + 'index' => $product_search_form_index++, + ) + ); + + $form = apply_filters( 'get_product_search_form', ob_get_clean() ); + + if ( ! $echo ) { + return $form; + } + + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo $form; + } +} + +if ( ! function_exists( 'woocommerce_output_auth_header' ) ) { + + /** + * Output the Auth header. + */ + function woocommerce_output_auth_header() { + wc_get_template( 'auth/header.php' ); + } +} + +if ( ! function_exists( 'woocommerce_output_auth_footer' ) ) { + + /** + * Output the Auth footer. + */ + function woocommerce_output_auth_footer() { + wc_get_template( 'auth/footer.php' ); + } +} + +if ( ! function_exists( 'woocommerce_single_variation' ) ) { + + /** + * Output placeholders for the single variation. + */ + function woocommerce_single_variation() { + echo ' '; + } + + $field_html .= '
'; + } +} + +if ( ! function_exists( 'woocommerce_single_variation_add_to_cart_button' ) ) { + + /** + * Output the add to cart button for variations. + */ + function woocommerce_single_variation_add_to_cart_button() { + wc_get_template( 'single-product/add-to-cart/variation-add-to-cart-button.php' ); + } +} + +if ( ! function_exists( 'wc_dropdown_variation_attribute_options' ) ) { + + /** + * Output a list of variation attributes for use in the cart forms. + * + * @param array $args Arguments. + * @since 2.4.0 + */ + function wc_dropdown_variation_attribute_options( $args = array() ) { + $args = wp_parse_args( + apply_filters( 'woocommerce_dropdown_variation_attribute_options_args', $args ), + array( + 'options' => false, + 'attribute' => false, + 'product' => false, + 'selected' => false, + 'name' => '', + 'id' => '', + 'class' => '', + 'show_option_none' => __( 'Choose an option', 'woocommerce' ), + ) + ); + + // Get selected value. + if ( false === $args['selected'] && $args['attribute'] && $args['product'] instanceof WC_Product ) { + $selected_key = 'attribute_' . sanitize_title( $args['attribute'] ); + // phpcs:disable WordPress.Security.NonceVerification.Recommended + $args['selected'] = isset( $_REQUEST[ $selected_key ] ) ? wc_clean( wp_unslash( $_REQUEST[ $selected_key ] ) ) : $args['product']->get_variation_default_attribute( $args['attribute'] ); + // phpcs:enable WordPress.Security.NonceVerification.Recommended + } + + $options = $args['options']; + $product = $args['product']; + $attribute = $args['attribute']; + $name = $args['name'] ? $args['name'] : 'attribute_' . sanitize_title( $attribute ); + $id = $args['id'] ? $args['id'] : sanitize_title( $attribute ); + $class = $args['class']; + $show_option_none = (bool) $args['show_option_none']; + $show_option_none_text = $args['show_option_none'] ? $args['show_option_none'] : __( 'Choose an option', 'woocommerce' ); // We'll do our best to hide the placeholder, but we'll need to show something when resetting options. + + if ( empty( $options ) && ! empty( $product ) && ! empty( $attribute ) ) { + $attributes = $product->get_variation_attributes(); + $options = $attributes[ $attribute ]; + } + + $html = ''; + + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo apply_filters( 'woocommerce_dropdown_variation_attribute_options_html', $html, $args ); + } +} + +if ( ! function_exists( 'woocommerce_account_content' ) ) { + + /** + * My Account content output. + */ + function woocommerce_account_content() { + global $wp; + + if ( ! empty( $wp->query_vars ) ) { + foreach ( $wp->query_vars as $key => $value ) { + // Ignore pagename param. + if ( 'pagename' === $key ) { + continue; + } + + if ( has_action( 'woocommerce_account_' . $key . '_endpoint' ) ) { + do_action( 'woocommerce_account_' . $key . '_endpoint', $value ); + return; + } + } + } + + // No endpoint found? Default to dashboard. + wc_get_template( + 'myaccount/dashboard.php', + array( + 'current_user' => get_user_by( 'id', get_current_user_id() ), + ) + ); + } +} + +if ( ! function_exists( 'woocommerce_account_navigation' ) ) { + + /** + * My Account navigation template. + */ + function woocommerce_account_navigation() { + wc_get_template( 'myaccount/navigation.php' ); + } +} + +if ( ! function_exists( 'woocommerce_account_orders' ) ) { + + /** + * My Account > Orders template. + * + * @param int $current_page Current page number. + */ + function woocommerce_account_orders( $current_page ) { + $current_page = empty( $current_page ) ? 1 : absint( $current_page ); + $customer_orders = wc_get_orders( + apply_filters( + 'woocommerce_my_account_my_orders_query', + array( + 'customer' => get_current_user_id(), + 'page' => $current_page, + 'paginate' => true, + ) + ) + ); + + wc_get_template( + 'myaccount/orders.php', + array( + 'current_page' => absint( $current_page ), + 'customer_orders' => $customer_orders, + 'has_orders' => 0 < $customer_orders->total, + ) + ); + } +} + +if ( ! function_exists( 'woocommerce_account_view_order' ) ) { + + /** + * My Account > View order template. + * + * @param int $order_id Order ID. + */ + function woocommerce_account_view_order( $order_id ) { + WC_Shortcode_My_Account::view_order( absint( $order_id ) ); + } +} + +if ( ! function_exists( 'woocommerce_account_downloads' ) ) { + + /** + * My Account > Downloads template. + */ + function woocommerce_account_downloads() { + wc_get_template( 'myaccount/downloads.php' ); + } +} + +if ( ! function_exists( 'woocommerce_account_edit_address' ) ) { + + /** + * My Account > Edit address template. + * + * @param string $type Address type. + */ + function woocommerce_account_edit_address( $type ) { + $type = wc_edit_address_i18n( sanitize_title( $type ), true ); + + WC_Shortcode_My_Account::edit_address( $type ); + } +} + +if ( ! function_exists( 'woocommerce_account_payment_methods' ) ) { + + /** + * My Account > Downloads template. + */ + function woocommerce_account_payment_methods() { + wc_get_template( 'myaccount/payment-methods.php' ); + } +} + +if ( ! function_exists( 'woocommerce_account_add_payment_method' ) ) { + + /** + * My Account > Add payment method template. + */ + function woocommerce_account_add_payment_method() { + WC_Shortcode_My_Account::add_payment_method(); + } +} + +if ( ! function_exists( 'woocommerce_account_edit_account' ) ) { + + /** + * My Account > Edit account template. + */ + function woocommerce_account_edit_account() { + WC_Shortcode_My_Account::edit_account(); + } +} + +if ( ! function_exists( 'wc_no_products_found' ) ) { + + /** + * Handles the loop when no products were found/no product exist. + */ + function wc_no_products_found() { + wc_get_template( 'loop/no-products-found.php' ); + } +} + + +if ( ! function_exists( 'wc_get_email_order_items' ) ) { + /** + * Get HTML for the order items to be shown in emails. + * + * @param WC_Order $order Order object. + * @param array $args Arguments. + * + * @since 3.0.0 + * @return string + */ + function wc_get_email_order_items( $order, $args = array() ) { + ob_start(); + + $defaults = array( + 'show_sku' => false, + 'show_image' => false, + 'image_size' => array( 32, 32 ), + 'plain_text' => false, + 'sent_to_admin' => false, + ); + + $args = wp_parse_args( $args, $defaults ); + $template = $args['plain_text'] ? 'emails/plain/email-order-items.php' : 'emails/email-order-items.php'; + + wc_get_template( + $template, + apply_filters( + 'woocommerce_email_order_items_args', + array( + 'order' => $order, + 'items' => $order->get_items(), + 'show_download_links' => $order->is_download_permitted() && ! $args['sent_to_admin'], + 'show_sku' => $args['show_sku'], + 'show_purchase_note' => $order->is_paid() && ! $args['sent_to_admin'], + 'show_image' => $args['show_image'], + 'image_size' => $args['image_size'], + 'plain_text' => $args['plain_text'], + 'sent_to_admin' => $args['sent_to_admin'], + ) + ) + ); + + return apply_filters( 'woocommerce_email_order_items_table', ob_get_clean(), $order ); + } +} + +if ( ! function_exists( 'wc_display_item_meta' ) ) { + /** + * Display item meta data. + * + * @since 3.0.0 + * @param WC_Order_Item $item Order Item. + * @param array $args Arguments. + * @return string|void + */ + function wc_display_item_meta( $item, $args = array() ) { + $strings = array(); + $html = ''; + $args = wp_parse_args( + $args, + array( + 'before' => '
', + 'separator' => '
' . wp_kses_post( apply_filters( 'wc_empty_cart_message', __( 'Your cart is currently empty.', 'woocommerce' ) ) ) . '
'; +} + +/** + * Disable search engines indexing core, dynamic, cart/checkout pages. + * + * @since 3.2.0 + */ +function wc_page_noindex() { + if ( is_page( wc_get_page_id( 'cart' ) ) || is_page( wc_get_page_id( 'checkout' ) ) || is_page( wc_get_page_id( 'myaccount' ) ) ) { + wp_no_robots(); + } +} +add_action( 'wp_head', 'wc_page_noindex' ); + +/** + * Get a slug identifying the current theme. + * + * @since 3.3.0 + * @return string + */ +function wc_get_theme_slug_for_templates() { + return apply_filters( 'woocommerce_theme_slug_for_templates', get_option( 'template' ) ); +} + +/** + * Gets and formats a list of cart item data + variations for display on the frontend. + * + * @since 3.3.0 + * @param array $cart_item Cart item object. + * @param bool $flat Should the data be returned flat or in a list. + * @return string + */ +function wc_get_formatted_cart_item_data( $cart_item, $flat = false ) { + $item_data = array(); + + // Variation values are shown only if they are not found in the title as of 3.0. + // This is because variation titles display the attributes. + if ( $cart_item['data']->is_type( 'variation' ) && is_array( $cart_item['variation'] ) ) { + foreach ( $cart_item['variation'] as $name => $value ) { + $taxonomy = wc_attribute_taxonomy_name( str_replace( 'attribute_pa_', '', urldecode( $name ) ) ); + + if ( taxonomy_exists( $taxonomy ) ) { + // If this is a term slug, get the term's nice name. + $term = get_term_by( 'slug', $value, $taxonomy ); + if ( ! is_wp_error( $term ) && $term && $term->name ) { + $value = $term->name; + } + $label = wc_attribute_label( $taxonomy ); + } else { + // If this is a custom option slug, get the options name. + $value = apply_filters( 'woocommerce_variation_option_name', $value, null, $taxonomy, $cart_item['data'] ); + $label = wc_attribute_label( str_replace( 'attribute_', '', $name ), $cart_item['data'] ); + } + + // Check the nicename against the title. + if ( '' === $value || wc_is_attribute_in_product_name( $value, $cart_item['data']->get_name() ) ) { + continue; + } + + $item_data[] = array( + 'key' => $label, + 'value' => $value, + ); + } + } + + // Filter item data to allow 3rd parties to add more to the array. + $item_data = apply_filters( 'woocommerce_get_item_data', $item_data, $cart_item ); + + // Format item data ready to display. + foreach ( $item_data as $key => $data ) { + // Set hidden to true to not display meta on cart. + if ( ! empty( $data['hidden'] ) ) { + unset( $item_data[ $key ] ); + continue; + } + $item_data[ $key ]['key'] = ! empty( $data['key'] ) ? $data['key'] : $data['name']; + $item_data[ $key ]['display'] = ! empty( $data['display'] ) ? $data['display'] : $data['value']; + } + + // Output flat or in list format. + if ( count( $item_data ) > 0 ) { + ob_start(); + + if ( $flat ) { + foreach ( $item_data as $data ) { + echo esc_html( $data['key'] ) . ': ' . wp_kses_post( $data['display'] ) . "\n"; + } + } else { + wc_get_template( 'cart/cart-item-data.php', array( 'item_data' => $item_data ) ); + } + + return ob_get_clean(); + } + + return ''; +} + +/** + * Gets the url to remove an item from the cart. + * + * @since 3.3.0 + * @param string $cart_item_key contains the id of the cart item. + * @return string url to page + */ +function wc_get_cart_remove_url( $cart_item_key ) { + $cart_page_url = wc_get_cart_url(); + return apply_filters( 'woocommerce_get_remove_url', $cart_page_url ? wp_nonce_url( add_query_arg( 'remove_item', $cart_item_key, $cart_page_url ), 'woocommerce-cart' ) : '' ); +} + +/** + * Gets the url to re-add an item into the cart. + * + * @since 3.3.0 + * @param string $cart_item_key Cart item key to undo. + * @return string url to page + */ +function wc_get_cart_undo_url( $cart_item_key ) { + $cart_page_url = wc_get_cart_url(); + + $query_args = array( + 'undo_item' => $cart_item_key, + ); + + return apply_filters( 'woocommerce_get_undo_url', $cart_page_url ? wp_nonce_url( add_query_arg( $query_args, $cart_page_url ), 'woocommerce-cart' ) : '', $cart_item_key ); +} + +/** + * Outputs all queued notices on WC pages. + * + * @since 3.5.0 + */ +function woocommerce_output_all_notices() { + echo '' . + __( 'Action Scheduler is a scalable, traceable job queue for background processing large sets of actions. Action Scheduler works by triggering an action hook to run at some time in the future. Scheduled actions can also be scheduled to run on a recurring schedule.', 'woocommerce' ) . + '
', + ) + ); + + $screen->add_help_tab( + array( + 'id' => 'action_scheduler_columns', + 'title' => __( 'Columns', 'woocommerce' ), + 'content' => + '%s => %s
' . $action->get_hook() . '
';
+ if ( 1 == $notification['success'] ) {
+ $class = 'updated';
+ switch ( $notification['row_action_type'] ) {
+ case 'run' :
+ /* translators: %s: action HTML */
+ $action_message_html = sprintf( __( 'Successfully executed action: %s', 'woocommerce' ), $action_hook_html );
+ break;
+ case 'cancel' :
+ /* translators: %s: action HTML */
+ $action_message_html = sprintf( __( 'Successfully canceled action: %s', 'woocommerce' ), $action_hook_html );
+ break;
+ default :
+ /* translators: %s: action HTML */
+ $action_message_html = sprintf( __( 'Successfully processed change for action: %s', 'woocommerce' ), $action_hook_html );
+ break;
+ }
+ } else {
+ $class = 'error';
+ /* translators: 1: action HTML 2: action ID 3: error message */
+ $action_message_html = sprintf( __( 'Could not process change for action: "%1$s" (ID: %2$d). Error: %3$s', 'woocommerce' ), $action_hook_html, esc_html( $notification['action_id'] ), esc_html( $notification['error_message'] ) );
+ }
+
+ $action_message_html = apply_filters( 'action_scheduler_admin_notice_html', $action_message_html, $action, $notification );
+
+ $this->admin_notices[] = array(
+ 'class' => $class,
+ 'message' => $action_message_html,
+ );
+ }
+
+ parent::display_admin_notices();
+ }
+
+ /**
+ * Prints the scheduled date in a human friendly format.
+ *
+ * @param array $row The array representation of the current row of the table
+ *
+ * @return string
+ */
+ public function column_schedule( $row ) {
+ return $this->get_schedule_display_string( $row['schedule'] );
+ }
+
+ /**
+ * Get the scheduled date in a human friendly format.
+ *
+ * @param ActionScheduler_Schedule $schedule
+ * @return string
+ */
+ protected function get_schedule_display_string( ActionScheduler_Schedule $schedule ) {
+
+ $schedule_display_string = '';
+
+ if ( ! $schedule->get_date() ) {
+ return '0000-00-00 00:00:00';
+ }
+
+ $next_timestamp = $schedule->get_date()->getTimestamp();
+
+ $schedule_display_string .= $schedule->get_date()->format( 'Y-m-d H:i:s O' );
+ $schedule_display_string .= '' . wp_kses_post( $notice ) . '
+ | ||||
---|---|---|---|---|
+ | + | |||
+ | + | + | + | + |
%1$s | %2$s | %3$s | %4$s |
' . wp_kses_post( $notice['message'] ) . '
'; + echo '%s
=0;n--){for(var u=t.words[n],l=c-1;l>=0;l--){var h=u>>l&1;i!==r[0]&&(i=this.sqr(i)),0!==h||0!==a?(a<<=1,a|=h,(4===++s||0===n&&0===l)&&(i=this.mul(i,r[a]),s=0,a=0)):s=0}c=26}return i},_.prototype.convertTo=function(e){var t=e.umod(this.m);return t===e?t.clone():t},_.prototype.convertFrom=function(e){var t=e.clone();return t.red=null,t},o.mont=function(e){return new O(e)},i(O,_),O.prototype.convertTo=function(e){return this.imod(e.ushln(this.shift))},O.prototype.convertFrom=function(e){var t=this.imod(e.mul(this.rinv));return t.red=null,t},O.prototype.imul=function(e,t){if(e.isZero()||t.isZero())return e.words[0]=0,e.length=1,e;var r=e.imul(t),n=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),i=r.isub(n).iushrn(this.shift),o=i;return i.cmp(this.m)>=0?o=i.isub(this.m):i.cmpn(0)<0&&(o=i.iadd(this.m)),o._forceRed(this)},O.prototype.mul=function(e,t){if(e.isZero()||t.isZero())return new o(0)._forceRed(this);var r=e.mul(t),n=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),i=r.isub(n).iushrn(this.shift),a=i;return i.cmp(this.m)>=0?a=i.isub(this.m):i.cmpn(0)<0&&(a=i.iadd(this.m)),a._forceRed(this)},O.prototype.invm=function(e){return this.imod(e._invmp(this.m).mul(this.r2))._forceRed(this)}}(e,this)}).call(this,r(80)(e))},,,,function(e,t){e.exports=function(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r