@charset "UTF-8";.elementor-widget-loop-grid{scroll-margin-top:var(--auto-scroll-offset,initial)}.elementor-widget-loop-grid-1 .elementor-grid{grid-template-columns:repeat(1,minmax(0,1fr))}.elementor-widget-loop-grid-2 .elementor-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.elementor-widget-loop-grid-3 .elementor-grid{grid-template-columns:repeat(3,minmax(0,1fr))}.elementor-widget-loop-grid-4 .elementor-grid{grid-template-columns:repeat(4,minmax(0,1fr))}.elementor-widget-loop-grid-5 .elementor-grid{grid-template-columns:repeat(5,minmax(0,1fr))}.elementor-widget-loop-grid-6 .elementor-grid{grid-template-columns:repeat(6,minmax(0,1fr))}.elementor-widget-loop-grid-7 .elementor-grid{grid-template-columns:repeat(7,minmax(0,1fr))}.elementor-widget-loop-grid-8 .elementor-grid{grid-template-columns:repeat(8,minmax(0,1fr))}.elementor-widget-loop-grid-9 .elementor-grid{grid-template-columns:repeat(9,minmax(0,1fr))}.elementor-widget-loop-grid-10 .elementor-grid{grid-template-columns:repeat(10,minmax(0,1fr))}.elementor-widget-loop-grid-11 .elementor-grid{grid-template-columns:repeat(11,minmax(0,1fr))}.elementor-widget-loop-grid-12 .elementor-grid{grid-template-columns:repeat(12,minmax(0,1fr))}@media (min-width:ELEMENTOR_SCREEN_WIDESCREEN_MIN){.elementor-widget-loop-grid-widescreen-1 .elementor-grid{grid-template-columns:repeat(1,minmax(0,1fr))}.elementor-widget-loop-grid-widescreen-2 .elementor-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.elementor-widget-loop-grid-widescreen-3 .elementor-grid{grid-template-columns:repeat(3,minmax(0,1fr))}.elementor-widget-loop-grid-widescreen-4 .elementor-grid{grid-template-columns:repeat(4,minmax(0,1fr))}.elementor-widget-loop-grid-widescreen-5 .elementor-grid{grid-template-columns:repeat(5,minmax(0,1fr))}.elementor-widget-loop-grid-widescreen-6 .elementor-grid{grid-template-columns:repeat(6,minmax(0,1fr))}.elementor-widget-loop-grid-widescreen-7 .elementor-grid{grid-template-columns:repeat(7,minmax(0,1fr))}.elementor-widget-loop-grid-widescreen-8 .elementor-grid{grid-template-columns:repeat(8,minmax(0,1fr))}.elementor-widget-loop-grid-widescreen-9 .elementor-grid{grid-template-columns:repeat(9,minmax(0,1fr))}.elementor-widget-loop-grid-widescreen-10 .elementor-grid{grid-template-columns:repeat(10,minmax(0,1fr))}.elementor-widget-loop-grid-widescreen-11 .elementor-grid{grid-template-columns:repeat(11,minmax(0,1fr))}.elementor-widget-loop-grid-widescreen-12 .elementor-grid{grid-template-columns:repeat(12,minmax(0,1fr))}}@media (max-width:ELEMENTOR_SCREEN_LAPTOP_MAX){.elementor-widget-loop-grid-laptop-1 .elementor-grid{grid-template-columns:repeat(1,minmax(0,1fr))}.elementor-widget-loop-grid-laptop-2 .elementor-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.elementor-widget-loop-grid-laptop-3 .elementor-grid{grid-template-columns:repeat(3,minmax(0,1fr))}.elementor-widget-loop-grid-laptop-4 .elementor-grid{grid-template-columns:repeat(4,minmax(0,1fr))}.elementor-widget-loop-grid-laptop-5 .elementor-grid{grid-template-columns:repeat(5,minmax(0,1fr))}.elementor-widget-loop-grid-laptop-6 .elementor-grid{grid-template-columns:repeat(6,minmax(0,1fr))}.elementor-widget-loop-grid-laptop-7 .elementor-grid{grid-template-columns:repeat(7,minmax(0,1fr))}.elementor-widget-loop-grid-laptop-8 .elementor-grid{grid-template-columns:repeat(8,minmax(0,1fr))}.elementor-widget-loop-grid-laptop-9 .elementor-grid{grid-template-columns:repeat(9,minmax(0,1fr))}.elementor-widget-loop-grid-laptop-10 .elementor-grid{grid-template-columns:repeat(10,minmax(0,1fr))}.elementor-widget-loop-grid-laptop-11 .elementor-grid{grid-template-columns:repeat(11,minmax(0,1fr))}.elementor-widget-loop-grid-laptop-12 .elementor-grid{grid-template-columns:repeat(12,minmax(0,1fr))}}@media (max-width:ELEMENTOR_SCREEN_TABLET_EXTRA_MAX){.elementor-widget-loop-grid-tablet_extra-1 .elementor-grid{grid-template-columns:repeat(1,minmax(0,1fr))}.elementor-widget-loop-grid-tablet_extra-2 .elementor-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.elementor-widget-loop-grid-tablet_extra-3 .elementor-grid{grid-template-columns:repeat(3,minmax(0,1fr))}.elementor-widget-loop-grid-tablet_extra-4 .elementor-grid{grid-template-columns:repeat(4,minmax(0,1fr))}.elementor-widget-loop-grid-tablet_extra-5 .elementor-grid{grid-template-columns:repeat(5,minmax(0,1fr))}.elementor-widget-loop-grid-tablet_extra-6 .elementor-grid{grid-template-columns:repeat(6,minmax(0,1fr))}.elementor-widget-loop-grid-tablet_extra-7 .elementor-grid{grid-template-columns:repeat(7,minmax(0,1fr))}.elementor-widget-loop-grid-tablet_extra-8 .elementor-grid{grid-template-columns:repeat(8,minmax(0,1fr))}.elementor-widget-loop-grid-tablet_extra-9 .elementor-grid{grid-template-columns:repeat(9,minmax(0,1fr))}.elementor-widget-loop-grid-tablet_extra-10 .elementor-grid{grid-template-columns:repeat(10,minmax(0,1fr))}.elementor-widget-loop-grid-tablet_extra-11 .elementor-grid{grid-template-columns:repeat(11,minmax(0,1fr))}.elementor-widget-loop-grid-tablet_extra-12 .elementor-grid{grid-template-columns:repeat(12,minmax(0,1fr))}}@media (max-width:ELEMENTOR_SCREEN_TABLET_MAX){.elementor-widget-loop-grid-tablet-1 .elementor-grid{grid-template-columns:repeat(1,minmax(0,1fr))}.elementor-widget-loop-grid-tablet-2 .elementor-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.elementor-widget-loop-grid-tablet-3 .elementor-grid{grid-template-columns:repeat(3,minmax(0,1fr))}.elementor-widget-loop-grid-tablet-4 .elementor-grid{grid-template-columns:repeat(4,minmax(0,1fr))}.elementor-widget-loop-grid-tablet-5 .elementor-grid{grid-template-columns:repeat(5,minmax(0,1fr))}.elementor-widget-loop-grid-tablet-6 .elementor-grid{grid-template-columns:repeat(6,minmax(0,1fr))}.elementor-widget-loop-grid-tablet-7 .elementor-grid{grid-template-columns:repeat(7,minmax(0,1fr))}.elementor-widget-loop-grid-tablet-8 .elementor-grid{grid-template-columns:repeat(8,minmax(0,1fr))}.elementor-widget-loop-grid-tablet-9 .elementor-grid{grid-template-columns:repeat(9,minmax(0,1fr))}.elementor-widget-loop-grid-tablet-10 .elementor-grid{grid-template-columns:repeat(10,minmax(0,1fr))}.elementor-widget-loop-grid-tablet-11 .elementor-grid{grid-template-columns:repeat(11,minmax(0,1fr))}.elementor-widget-loop-grid-tablet-12 .elementor-grid{grid-template-columns:repeat(12,minmax(0,1fr))}}@media (max-width:ELEMENTOR_SCREEN_MOBILE_EXTRA_MAX){.elementor-widget-loop-grid-mobile_extra-1 .elementor-grid{grid-template-columns:repeat(1,minmax(0,1fr))}.elementor-widget-loop-grid-mobile_extra-2 .elementor-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.elementor-widget-loop-grid-mobile_extra-3 .elementor-grid{grid-template-columns:repeat(3,minmax(0,1fr))}.elementor-widget-loop-grid-mobile_extra-4 .elementor-grid{grid-template-columns:repeat(4,minmax(0,1fr))}.elementor-widget-loop-grid-mobile_extra-5 .elementor-grid{grid-template-columns:repeat(5,minmax(0,1fr))}.elementor-widget-loop-grid-mobile_extra-6 .elementor-grid{grid-template-columns:repeat(6,minmax(0,1fr))}.elementor-widget-loop-grid-mobile_extra-7 .elementor-grid{grid-template-columns:repeat(7,minmax(0,1fr))}.elementor-widget-loop-grid-mobile_extra-8 .elementor-grid{grid-template-columns:repeat(8,minmax(0,1fr))}.elementor-widget-loop-grid-mobile_extra-9 .elementor-grid{grid-template-columns:repeat(9,minmax(0,1fr))}.elementor-widget-loop-grid-mobile_extra-10 .elementor-grid{grid-template-columns:repeat(10,minmax(0,1fr))}.elementor-widget-loop-grid-mobile_extra-11 .elementor-grid{grid-template-columns:repeat(11,minmax(0,1fr))}.elementor-widget-loop-grid-mobile_extra-12 .elementor-grid{grid-template-columns:repeat(12,minmax(0,1fr))}}@media (max-width:ELEMENTOR_SCREEN_MOBILE_MAX){.elementor-widget-loop-grid-mobile-1 .elementor-grid{grid-template-columns:repeat(1,minmax(0,1fr))}.elementor-widget-loop-grid-mobile-2 .elementor-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.elementor-widget-loop-grid-mobile-3 .elementor-grid{grid-template-columns:repeat(3,minmax(0,1fr))}.elementor-widget-loop-grid-mobile-4 .elementor-grid{grid-template-columns:repeat(4,minmax(0,1fr))}.elementor-widget-loop-grid-mobile-5 .elementor-grid{grid-template-columns:repeat(5,minmax(0,1fr))}.elementor-widget-loop-grid-mobile-6 .elementor-grid{grid-template-columns:repeat(6,minmax(0,1fr))}.elementor-widget-loop-grid-mobile-7 .elementor-grid{grid-template-columns:repeat(7,minmax(0,1fr))}.elementor-widget-loop-grid-mobile-8 .elementor-grid{grid-template-columns:repeat(8,minmax(0,1fr))}.elementor-widget-loop-grid-mobile-9 .elementor-grid{grid-template-columns:repeat(9,minmax(0,1fr))}.elementor-widget-loop-grid-mobile-10 .elementor-grid{grid-template-columns:repeat(10,minmax(0,1fr))}.elementor-widget-loop-grid-mobile-11 .elementor-grid{grid-template-columns:repeat(11,minmax(0,1fr))}.elementor-widget-loop-grid-mobile-12 .elementor-grid{grid-template-columns:repeat(12,minmax(0,1fr))}}.elementor-widget-loop-grid .elementor-grid{grid-column-gap:var(--grid-column-gap,30px);grid-row-gap:var(--grid-row-gap,30px)}.elementor-widget-loop-grid.e-loading-overlay{animation:loadingOpacityAnimation 1s infinite alternate}.elementor-widget-loop-grid .e-loop__load-more{text-align:var(--load-more-button-align)}.elementor-widget-loop-grid .e-loop__load-more .elementor-button{width:var(--load-more-button-width)}.elementor-widget-loop-grid.e-load-more-pagination-loading>.elementor-widget-container{cursor:default}.elementor-widget-loop-grid.e-load-more-pagination-loading>.elementor-widget-container .e-load-more-spinner{margin-top:var(--load-more—spacing,30px)}.elementor-widget-loop-grid.e-load-more-pagination-loading>.elementor-widget-container .e-load-more-spinner i,.elementor-widget-loop-grid.e-load-more-pagination-loading>.elementor-widget-container .e-load-more-spinner svg{display:flex}.elementor-widget-loop-grid.e-load-more-pagination-loading>.elementor-widget-container>.elementor-button-wrapper .elementor-button-content-wrapper{visibility:hidden}.elementor-widget-loop-grid.e-load-more-pagination-end:not(:has(>.elementor-widget-container))>.elementor-button-wrapper,.elementor-widget-loop-grid.e-load-more-pagination-end>.elementor-widget-container>.elementor-button-wrapper{display:none}.elementor-widget-loop-grid.e-load-more-pagination-end:not(:has(>.elementor-widget-container))>.e-load-more-message,.elementor-widget-loop-grid.e-load-more-pagination-end>.elementor-widget-container>.e-load-more-message{display:block}.elementor-widget-loop-grid.e-load-more-no-spinner:not(:has(>.elementor-widget-container))>.elementor-button-wrapper .elementor-button-content-wrapper,.elementor-widget-loop-grid.e-load-more-no-spinner>.elementor-widget-container>.elementor-button-wrapper .elementor-button-content-wrapper{visibility:visible}.elementor-widget-loop-grid:not(:has(>.elementor-widget-container)) .e-load-more-spinner,.elementor-widget-loop-grid>.elementor-widget-container .e-load-more-spinner{display:flex}.elementor-widget-loop-grid:not(:has(>.elementor-widget-container)) .e-load-more-spinner i,.elementor-widget-loop-grid:not(:has(>.elementor-widget-container)) .e-load-more-spinner svg,.elementor-widget-loop-grid>.elementor-widget-container .e-load-more-spinner i,.elementor-widget-loop-grid>.elementor-widget-container .e-load-more-spinner svg{display:none;margin:0 auto}.elementor-widget-loop-grid:not(:has(>.elementor-widget-container)) .e-load-more-spinner i,.elementor-widget-loop-grid>.elementor-widget-container .e-load-more-spinner i{color:var(--load-more-spinner-color)}.elementor-widget-loop-grid:not(:has(>.elementor-widget-container)) .e-load-more-spinner svg,.elementor-widget-loop-grid>.elementor-widget-container .e-load-more-spinner svg{fill:var(--load-more-spinner-color);height:1em;width:1em}.elementor-widget-loop-grid:not(:has(>.elementor-widget-container)) .e-load-more-message,.elementor-widget-loop-grid>.elementor-widget-container .e-load-more-message{color:var(--load-more-message-color);display:none;margin-top:var(--load-more—spacing,30px);text-align:var(--load-more-message-alignment,center)}.elementor-widget-loop-grid:not(:has(>.elementor-widget-container))>.elementor-button-wrapper,.elementor-widget-loop-grid>.elementor-widget-container>.elementor-button-wrapper{margin-top:var(--load-more—spacing,30px)}.elementor-widget-loop-grid:not(:has(>.elementor-widget-container))>.elementor-button-wrapper .e-load-more-spinner,.elementor-widget-loop-grid>.elementor-widget-container>.elementor-button-wrapper .e-load-more-spinner{inset-block-start:50%;inset-inline-start:50%;margin:inherit;position:absolute;transform:translate(-50%,-50%)}.elementor-widget-loop-grid:not(:has(>.elementor-widget-container))>.elementor-button-wrapper .elementor-button,.elementor-widget-loop-grid>.elementor-widget-container>.elementor-button-wrapper .elementor-button{cursor:pointer;position:relative}.elementor-widget-loop-grid .e-loop-nothing-found-message{color:var(--e-loop-nothing-found-message-color,#1f2124);padding-block-end:var(--e-loop-nothing-found-message-space-from-bottom,30px);padding-block-start:var(--e-loop-nothing-found-message-space-from-top,30px);text-align:var(--e-loop-nothing-found-message-align,center)}.elementor-loop-container.elementor-posts-masonry{align-items:flex-start}.elementor-loop-container:not(.elementor-posts-masonry){align-items:stretch}@keyframes loadingOpacityAnimation{0%,to{opacity:1}50%{opacity:.6}}/** * WooCommerce Stock Functions * * Functions used to manage product stock levels. * * @package WooCommerce\Functions * @version 3.4.0 */ defined( 'ABSPATH' ) || exit; /** * Update a product's stock amount. * * Uses queries rather than update_post_meta so we can do this in one query (to avoid stock issues). * * @since 3.0.0 this supports set, increase and decrease. * * @param int|WC_Product $product Product ID or product instance. * @param int|null $stock_quantity Stock quantity. * @param string $operation Type of operation, allows 'set', 'increase' and 'decrease'. * @param bool $updating If true, the product object won't be saved here as it will be updated later. * @return bool|int|null */ function wc_update_product_stock( $product, $stock_quantity = null, $operation = 'set', $updating = false ) { if ( ! is_a( $product, 'WC_Product' ) ) { $product = wc_get_product( $product ); } if ( ! $product ) { return false; } if ( ! is_null( $stock_quantity ) && $product->managing_stock() ) { // Some products (variations) can have their stock managed by their parent. Get the correct object to be updated here. $product_id_with_stock = $product->get_stock_managed_by_id(); $product_with_stock = $product_id_with_stock !== $product->get_id() ? wc_get_product( $product_id_with_stock ) : $product; $data_store = WC_Data_Store::load( 'product' ); // Fire actions to let 3rd parties know the stock is about to be changed. if ( $product_with_stock->is_type( 'variation' ) ) { do_action( 'woocommerce_variation_before_set_stock', $product_with_stock ); } else { do_action( 'woocommerce_product_before_set_stock', $product_with_stock ); } // Update the database. $new_stock = $data_store->update_product_stock( $product_id_with_stock, $stock_quantity, $operation ); // Update the product object. $data_store->read_stock_quantity( $product_with_stock, $new_stock ); // If this is not being called during an update routine, save the product so stock status etc is in sync, and caches are cleared. if ( ! $updating ) { $product_with_stock->save(); } // Fire actions to let 3rd parties know the stock changed. if ( $product_with_stock->is_type( 'variation' ) ) { do_action( 'woocommerce_variation_set_stock', $product_with_stock ); } else { do_action( 'woocommerce_product_set_stock', $product_with_stock ); } return $product_with_stock->get_stock_quantity(); } return $product->get_stock_quantity(); } /** * Update a product's stock status. * * @param int $product_id Product ID. * @param string $status Status. */ function wc_update_product_stock_status( $product_id, $status ) { $product = wc_get_product( $product_id ); if ( $product ) { $product->set_stock_status( $status ); $product->save(); } } /** * When a payment is complete, we can reduce stock levels for items within an order. * * @since 3.0.0 * @param int $order_id Order ID. */ function wc_maybe_reduce_stock_levels( $order_id ) { $order = wc_get_order( $order_id ); if ( ! $order ) { return; } $stock_reduced = $order->get_data_store()->get_stock_reduced( $order_id ); $trigger_reduce = apply_filters( 'woocommerce_payment_complete_reduce_order_stock', ! $stock_reduced, $order_id ); // Only continue if we're reducing stock. if ( ! $trigger_reduce ) { return; } wc_reduce_stock_levels( $order ); // Ensure stock is marked as "reduced" in case payment complete or other stock actions are called. $order->get_data_store()->set_stock_reduced( $order_id, true ); } add_action( 'woocommerce_payment_complete', 'wc_maybe_reduce_stock_levels' ); add_action( 'woocommerce_order_status_completed', 'wc_maybe_reduce_stock_levels' ); add_action( 'woocommerce_order_status_processing', 'wc_maybe_reduce_stock_levels' ); add_action( 'woocommerce_order_status_on-hold', 'wc_maybe_reduce_stock_levels' ); /** * When a payment is cancelled, restore stock. * * @since 3.0.0 * @param int $order_id Order ID. */ function wc_maybe_increase_stock_levels( $order_id ) { $order = wc_get_order( $order_id ); if ( ! $order ) { return; } $stock_reduced = $order->get_data_store()->get_stock_reduced( $order_id ); $trigger_increase = (bool) $stock_reduced; // Only continue if we're increasing stock. if ( ! $trigger_increase ) { return; } wc_increase_stock_levels( $order ); // Ensure stock is not marked as "reduced" anymore. $order->get_data_store()->set_stock_reduced( $order_id, false ); } add_action( 'woocommerce_order_status_cancelled', 'wc_maybe_increase_stock_levels' ); add_action( 'woocommerce_order_status_pending', 'wc_maybe_increase_stock_levels' ); /** * Reduce stock levels for items within an order, if stock has not already been reduced for the items. * * @since 3.0.0 * @param int|WC_Order $order_id Order ID or order instance. */ function wc_reduce_stock_levels( $order_id ) { if ( is_a( $order_id, 'WC_Order' ) ) { $order = $order_id; $order_id = $order->get_id(); } else { $order = wc_get_order( $order_id ); } // We need an order, and a store with stock management to continue. if ( ! $order || 'yes' !== get_option( 'woocommerce_manage_stock' ) || ! apply_filters( 'woocommerce_can_reduce_order_stock', true, $order ) ) { return; } $changes = array(); // Loop over all items. foreach ( $order->get_items() as $item ) { if ( ! $item->is_type( 'line_item' ) ) { continue; } // Only reduce stock once for each item. $product = $item->get_product(); $item_stock_reduced = $item->get_meta( '_reduced_stock', true ); if ( $item_stock_reduced || ! $product || ! $product->managing_stock() ) { continue; } /** * Filter order item quantity. * * @param int|float $quantity Quantity. * @param WC_Order $order Order data. * @param WC_Order_Item_Product $item Order item data. */ $qty = apply_filters( 'woocommerce_order_item_quantity', $item->get_quantity(), $order, $item ); $item_name = $product->get_formatted_name(); $new_stock = wc_update_product_stock( $product, $qty, 'decrease' ); if ( is_wp_error( $new_stock ) ) { /* translators: %s item name. */ $order->add_order_note( sprintf( __( 'Unable to reduce stock for item %s.', 'woocommerce' ), $item_name ) ); continue; } $item->add_meta_data( '_reduced_stock', $qty, true ); $item->save(); $change = array( 'product' => $product, 'from' => $new_stock + $qty, 'to' => $new_stock, ); $changes[] = $change; /** * Fires when stock reduced to a specific line item * * @param WC_Order_Item_Product $item Order item data. * @param array $change Change Details. * @param WC_Order $order Order data. * @since 7.6.0 */ do_action( 'woocommerce_reduce_order_item_stock', $item, $change, $order ); } wc_trigger_stock_change_notifications( $order, $changes ); do_action( 'woocommerce_reduce_order_stock', $order ); } /** * After stock change events, triggers emails and adds order notes. * * @since 3.5.0 * @param WC_Order $order order object. * @param array $changes Array of changes. */ function wc_trigger_stock_change_notifications( $order, $changes ) { if ( empty( $changes ) ) { return; } $order_notes = array(); $no_stock_amount = absint( get_option( 'woocommerce_notify_no_stock_amount', 0 ) ); foreach ( $changes as $change ) { $order_notes[] = $change['product']->get_formatted_name() . ' ' . $change['from'] . '→' . $change['to']; $low_stock_amount = absint( wc_get_low_stock_amount( wc_get_product( $change['product']->get_id() ) ) ); if ( $change['to'] <= $no_stock_amount ) { do_action( 'woocommerce_no_stock', wc_get_product( $change['product']->get_id() ) ); } elseif ( $change['to'] <= $low_stock_amount ) { do_action( 'woocommerce_low_stock', wc_get_product( $change['product']->get_id() ) ); } if ( $change['to'] < 0 ) { do_action( 'woocommerce_product_on_backorder', array( 'product' => wc_get_product( $change['product']->get_id() ), 'order_id' => $order->get_id(), 'quantity' => abs( $change['from'] - $change['to'] ), ) ); } } $order->add_order_note( __( 'Stock levels reduced:', 'woocommerce' ) . ' ' . implode( ', ', $order_notes ) ); } /** * Increase stock levels for items within an order. * * @since 3.0.0 * @param int|WC_Order $order_id Order ID or order instance. */ function wc_increase_stock_levels( $order_id ) { if ( is_a( $order_id, 'WC_Order' ) ) { $order = $order_id; $order_id = $order->get_id(); } else { $order = wc_get_order( $order_id ); } // We need an order, and a store with stock management to continue. if ( ! $order || 'yes' !== get_option( 'woocommerce_manage_stock' ) || ! apply_filters( 'woocommerce_can_restore_order_stock', true, $order ) ) { return; } $changes = array(); // Loop over all items. foreach ( $order->get_items() as $item ) { if ( ! $item->is_type( 'line_item' ) ) { continue; } // Only increase stock once for each item. $product = $item->get_product(); $item_stock_reduced = $item->get_meta( '_reduced_stock', true ); if ( ! $item_stock_reduced || ! $product || ! $product->managing_stock() ) { continue; } $item_name = $product->get_formatted_name(); $new_stock = wc_update_product_stock( $product, $item_stock_reduced, 'increase' ); if ( is_wp_error( $new_stock ) ) { /* translators: %s item name. */ $order->add_order_note( sprintf( __( 'Unable to restore stock for item %s.', 'woocommerce' ), $item_name ) ); continue; } $item->delete_meta_data( '_reduced_stock' ); $item->save(); $changes[] = $item_name . ' ' . ( $new_stock - $item_stock_reduced ) . '→' . $new_stock; } if ( $changes ) { $order->add_order_note( __( 'Stock levels increased:', 'woocommerce' ) . ' ' . implode( ', ', $changes ) ); } do_action( 'woocommerce_restore_order_stock', $order ); } /** * See how much stock is being held in pending orders. * * @since 3.5.0 * @param WC_Product $product Product to check. * @param integer $exclude_order_id Order ID to exclude. * @return int */ function wc_get_held_stock_quantity( WC_Product $product, $exclude_order_id = 0 ) { /** * Filter: woocommerce_hold_stock_for_checkout * Allows enable/disable hold stock functionality on checkout. * * @since 4.3.0 * @param bool $enabled Default to true if managing stock globally. */ if ( ! apply_filters( 'woocommerce_hold_stock_for_checkout', wc_string_to_bool( get_option( 'woocommerce_manage_stock', 'yes' ) ) ) ) { return 0; } return ( new \Automattic\WooCommerce\Checkout\Helpers\ReserveStock() )->get_reserved_stock( $product, $exclude_order_id ); } /** * Hold stock for an order. * * @throws ReserveStockException If reserve stock fails. * * @since 4.1.0 * @param \WC_Order|int $order Order ID or instance. */ function wc_reserve_stock_for_order( $order ) { /** * Filter: woocommerce_hold_stock_for_checkout * Allows enable/disable hold stock functionality on checkout. * * @since @since 4.1.0 * @param bool $enabled Default to true if managing stock globally. */ if ( ! apply_filters( 'woocommerce_hold_stock_for_checkout', wc_string_to_bool( get_option( 'woocommerce_manage_stock', 'yes' ) ) ) ) { return; } $order = $order instanceof WC_Order ? $order : wc_get_order( $order ); if ( $order ) { ( new \Automattic\WooCommerce\Checkout\Helpers\ReserveStock() )->reserve_stock_for_order( $order ); } } add_action( 'woocommerce_checkout_order_created', 'wc_reserve_stock_for_order' ); /** * Release held stock for an order. * * @since 4.3.0 * @param \WC_Order|int $order Order ID or instance. */ function wc_release_stock_for_order( $order ) { /** * Filter: woocommerce_hold_stock_for_checkout * Allows enable/disable hold stock functionality on checkout. * * @since 4.3.0 * @param bool $enabled Default to true if managing stock globally. */ if ( ! apply_filters( 'woocommerce_hold_stock_for_checkout', wc_string_to_bool( get_option( 'woocommerce_manage_stock', 'yes' ) ) ) ) { return; } $order = $order instanceof WC_Order ? $order : wc_get_order( $order ); if ( $order ) { ( new \Automattic\WooCommerce\Checkout\Helpers\ReserveStock() )->release_stock_for_order( $order ); } } add_action( 'woocommerce_checkout_order_exception', 'wc_release_stock_for_order' ); add_action( 'woocommerce_payment_complete', 'wc_release_stock_for_order', 11 ); add_action( 'woocommerce_order_status_cancelled', 'wc_release_stock_for_order', 11 ); add_action( 'woocommerce_order_status_completed', 'wc_release_stock_for_order', 11 ); add_action( 'woocommerce_order_status_processing', 'wc_release_stock_for_order', 11 ); add_action( 'woocommerce_order_status_on-hold', 'wc_release_stock_for_order', 11 ); /** * Return low stock amount to determine if notification needs to be sent * * Since 5.2.0, this function no longer redirects from variation to its parent product. * Low stock amount can now be attached to the variation itself and if it isn't, only * then we check the parent product, and if it's not there, then we take the default * from the store-wide setting. * * @param WC_Product $product Product to get data from. * @since 3.5.0 * @return int */ function wc_get_low_stock_amount( WC_Product $product ) { $low_stock_amount = $product->get_low_stock_amount(); if ( '' === $low_stock_amount && $product->is_type( 'variation' ) ) { $product = wc_get_product( $product->get_parent_id() ); $low_stock_amount = $product->get_low_stock_amount(); } if ( '' === $low_stock_amount ) { $low_stock_amount = get_option( 'woocommerce_notify_low_stock_amount', 2 ); } return (int) $low_stock_amount; } /** * WooCommerce REST Functions * * Functions for REST specific things. * * @package WooCommerce\Functions * @version 2.6.0 */ defined( 'ABSPATH' ) || exit; /** * Parses and formats a date for ISO8601/RFC3339. * * Required WP 4.4 or later. * See https://developer.wordpress.org/reference/functions/mysql_to_rfc3339/ * * @since 2.6.0 * @param string|null|WC_DateTime $date Date. * @param bool $utc Send false to get local/offset time. * @return string|null ISO8601/RFC3339 formatted datetime. */ function wc_rest_prepare_date_response( $date, $utc = true ) { if ( is_numeric( $date ) ) { $date = new WC_DateTime( "@$date", new DateTimeZone( 'UTC' ) ); $date->setTimezone( new DateTimeZone( wc_timezone_string() ) ); } elseif ( is_string( $date ) ) { $date = new WC_DateTime( $date, new DateTimeZone( 'UTC' ) ); $date->setTimezone( new DateTimeZone( wc_timezone_string() ) ); } if ( ! is_a( $date, 'WC_DateTime' ) ) { return null; } // Get timestamp before changing timezone to UTC. return gmdate( 'Y-m-d\TH:i:s', $utc ? $date->getTimestamp() : $date->getOffsetTimestamp() ); } /** * Returns image mime types users are allowed to upload via the API. * * @since 2.6.4 * @return array */ function wc_rest_allowed_image_mime_types() { return apply_filters( 'woocommerce_rest_allowed_image_mime_types', array( 'jpg|jpeg|jpe' => 'image/jpeg', 'gif' => 'image/gif', 'png' => 'image/png', 'bmp' => 'image/bmp', 'tiff|tif' => 'image/tiff', 'ico' => 'image/x-icon', ) ); } /** * Upload image from URL. * * @since 2.6.0 * @param string $image_url Image URL. * @return array|WP_Error Attachment data or error message. */ function wc_rest_upload_image_from_url( $image_url ) { $parsed_url = wp_parse_url( $image_url ); // Check parsed URL. if ( ! $parsed_url || ! is_array( $parsed_url ) ) { /* translators: %s: image URL */ return new WP_Error( 'woocommerce_rest_invalid_image_url', sprintf( __( 'Invalid URL %s.', 'woocommerce' ), $image_url ), array( 'status' => 400 ) ); } // Ensure url is valid. $image_url = esc_url_raw( $image_url ); // download_url function is part of wp-admin. if ( ! function_exists( 'download_url' ) ) { include_once ABSPATH . 'wp-admin/includes/file.php'; } $file_array = array(); $file_array['name'] = basename( current( explode( '?', $image_url ) ) ); // Download file to temp location. $file_array['tmp_name'] = download_url( $image_url ); // If error storing temporarily, return the error. if ( is_wp_error( $file_array['tmp_name'] ) ) { return new WP_Error( 'woocommerce_rest_invalid_remote_image_url', /* translators: %s: image URL */ sprintf( __( 'Error getting remote image %s.', 'woocommerce' ), $image_url ) . ' ' /* translators: %s: error message */ . sprintf( __( 'Error: %s', 'woocommerce' ), $file_array['tmp_name']->get_error_message() ), array( 'status' => 400 ) ); } // Do the validation and storage stuff. $file = wp_handle_sideload( $file_array, array( 'test_form' => false, 'mimes' => wc_rest_allowed_image_mime_types(), ), current_time( 'Y/m' ) ); if ( isset( $file['error'] ) ) { @unlink( $file_array['tmp_name'] ); // @codingStandardsIgnoreLine. /* translators: %s: error message */ return new WP_Error( 'woocommerce_rest_invalid_image', sprintf( __( 'Invalid image: %s', 'woocommerce' ), $file['error'] ), array( 'status' => 400 ) ); } do_action( 'woocommerce_rest_api_uploaded_image_from_url', $file, $image_url ); return $file; } /** * Set uploaded image as attachment. * * @since 2.6.0 * @param array $upload Upload information from wp_upload_bits. * @param int $id Post ID. Default to 0. * @return int Attachment ID */ function wc_rest_set_uploaded_image_as_attachment( $upload, $id = 0 ) { $info = wp_check_filetype( $upload['file'] ); $title = ''; $content = ''; if ( ! function_exists( 'wp_generate_attachment_metadata' ) ) { include_once ABSPATH . 'wp-admin/includes/image.php'; } $image_meta = @wp_read_image_metadata( $upload['file'] ); if ( $image_meta ) { if ( trim( $image_meta['title'] ) && ! is_numeric( sanitize_title( $image_meta['title'] ) ) ) { $title = wc_clean( $image_meta['title'] ); } if ( trim( $image_meta['caption'] ) ) { $content = wc_clean( $image_meta['caption'] ); } } $attachment = array( 'post_mime_type' => $info['type'], 'guid' => $upload['url'], 'post_parent' => $id, 'post_title' => $title ? $title : basename( $upload['file'] ), 'post_content' => $content, ); $attachment_id = wp_insert_attachment( $attachment, $upload['file'], $id ); if ( ! is_wp_error( $attachment_id ) ) { @wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $upload['file'] ) ); } return $attachment_id; } /** * Validate reports request arguments. * * @since 2.6.0 * @param mixed $value Value to validate. * @param WP_REST_Request $request Request instance. * @param string $param Param to validate. * @return WP_Error|boolean */ function wc_rest_validate_reports_request_arg( $value, $request, $param ) { $attributes = $request->get_attributes(); if ( ! isset( $attributes['args'][ $param ] ) || ! is_array( $attributes['args'][ $param ] ) ) { return true; } $args = $attributes['args'][ $param ]; if ( 'string' === $args['type'] && ! is_string( $value ) ) { /* translators: 1: param 2: type */ return new WP_Error( 'woocommerce_rest_invalid_param', sprintf( __( '%1$s is not of type %2$s', 'woocommerce' ), $param, 'string' ) ); } if ( 'date' === $args['format'] ) { $regex = '#^\d{4}-\d{2}-\d{2}$#'; if ( ! preg_match( $regex, $value, $matches ) ) { return new WP_Error( 'woocommerce_rest_invalid_date', __( 'The date you provided is invalid.', 'woocommerce' ) ); } } return true; } /** * Encodes a value according to RFC 3986. * Supports multidimensional arrays. * * @since 2.6.0 * @param string|array $value The value to encode. * @return string|array Encoded values. */ function wc_rest_urlencode_rfc3986( $value ) { if ( is_array( $value ) ) { return array_map( 'wc_rest_urlencode_rfc3986', $value ); } return str_replace( array( '+', '%7E' ), array( ' ', '~' ), rawurlencode( $value ) ); } /** * Check permissions of posts on REST API. * * @since 2.6.0 * @param string $post_type Post type. * @param string $context Request context. * @param int $object_id Post ID. * @return bool */ function wc_rest_check_post_permissions( $post_type, $context = 'read', $object_id = 0 ) { $contexts = array( 'read' => 'read_private_posts', 'create' => 'publish_posts', 'edit' => 'edit_post', 'delete' => 'delete_post', 'batch' => 'edit_others_posts', ); if ( 'revision' === $post_type ) { $permission = false; } else { $cap = $contexts[ $context ]; $post_type_object = get_post_type_object( $post_type ); $permission = current_user_can( $post_type_object->cap->$cap, $object_id ); } return apply_filters( 'woocommerce_rest_check_permissions', $permission, $context, $object_id, $post_type ); } /** * Check permissions of users on REST API. * * @since 2.6.0 * @param string $context Request context. * @param int $object_id Post ID. * @return bool */ function wc_rest_check_user_permissions( $context = 'read', $object_id = 0 ) { $contexts = array( 'read' => 'list_users', 'create' => 'promote_users', // Check if current user can create users, shop managers are not allowed to create users. 'edit' => 'edit_users', 'delete' => 'delete_users', 'batch' => 'promote_users', ); // Check to allow shop_managers to manage only customers. if ( in_array( $context, array( 'edit', 'delete' ), true ) && wc_current_user_has_role( 'shop_manager' ) ) { $permission = false; $user_data = get_userdata( $object_id ); $shop_manager_editable_roles = apply_filters( 'woocommerce_shop_manager_editable_roles', array( 'customer' ) ); if ( isset( $user_data->roles ) ) { $can_manage_users = array_intersect( $user_data->roles, array_unique( $shop_manager_editable_roles ) ); // Check if Shop Manager can edit customer or with the is same shop manager. if ( 0 < count( $can_manage_users ) || intval( $object_id ) === intval( get_current_user_id() ) ) { $permission = current_user_can( $contexts[ $context ], $object_id ); } } } else { $permission = current_user_can( $contexts[ $context ], $object_id ); } return apply_filters( 'woocommerce_rest_check_permissions', $permission, $context, $object_id, 'user' ); } /** * Check permissions of product terms on REST API. * * @since 2.6.0 * @param string $taxonomy Taxonomy. * @param string $context Request context. * @param int $object_id Post ID. * @return bool */ function wc_rest_check_product_term_permissions( $taxonomy, $context = 'read', $object_id = 0 ) { $contexts = array( 'read' => 'manage_terms', 'create' => 'edit_terms', 'edit' => 'edit_terms', 'delete' => 'delete_terms', 'batch' => 'edit_terms', ); $cap = $contexts[ $context ]; $taxonomy_object = get_taxonomy( $taxonomy ); $permission = current_user_can( $taxonomy_object->cap->$cap, $object_id ); return apply_filters( 'woocommerce_rest_check_permissions', $permission, $context, $object_id, $taxonomy ); } /** * Check manager permissions on REST API. * * @since 2.6.0 * @param string $object Object. * @param string $context Request context. * @return bool */ function wc_rest_check_manager_permissions( $object, $context = 'read' ) { $objects = array( 'reports' => 'view_woocommerce_reports', 'settings' => 'manage_woocommerce', 'system_status' => 'manage_woocommerce', 'attributes' => 'manage_product_terms', 'shipping_methods' => 'manage_woocommerce', 'payment_gateways' => 'manage_woocommerce', 'webhooks' => 'manage_woocommerce', ); $permission = current_user_can( $objects[ $object ] ); return apply_filters( 'woocommerce_rest_check_permissions', $permission, $context, 0, $object ); } /** * Check product reviews permissions on REST API. * * @since 3.5.0 * @param string $context Request context. * @param string $object_id Object ID. * @return bool */ function wc_rest_check_product_reviews_permissions( $context = 'read', $object_id = 0 ) { $permission = false; $contexts = array( 'read' => 'moderate_comments', 'create' => 'edit_products', 'edit' => 'edit_products', 'delete' => 'edit_products', 'batch' => 'edit_products', ); if ( $object_id > 0 ) { $object = get_comment( $object_id ); if ( ! is_a( $object, 'WP_Comment' ) || get_comment_type( $object ) !== 'review' ) { return false; } } if ( isset( $contexts[ $context ] ) ) { $permission = current_user_can( $contexts[ $context ], $object_id ); } return apply_filters( 'woocommerce_rest_check_permissions', $permission, $context, $object_id, 'product_review' ); } /** * Normalize a filesystem path. */ if (!function_exists('wp_normalize_path')) { /** * WordPress function to normalize a filesystem path; was added to WP core in WP 3.9 * * @see wp_normalize_path() https://developer.wordpress.org/reference/functions/wp_normalize_path/#source for the original source code * * @param string $path Path to normalize. * @return string Normalized path. */ function wp_normalize_path($path) { $wrapper = ''; if (wp_is_stream($path)) { list($wrapper, $path) = explode('://', $path, 2); $wrapper .= '://'; } // Standardise all paths to use / $path = str_replace('\\', '/', $path); // Replace multiple slashes down to a singular, allowing for network shares having two slashes. $path = preg_replace('|(?<=.)/+|', '/', $path); // Windows paths should uppercase the drive letter if (':' === substr($path, 1, 1)) { $path = ucfirst($path); } return $wrapper.$path; } } /** * Unschedules all events attached to the hook. */ if (!function_exists('wp_unschedule_hook')) { /** * Unschedules all events attached to the hook. * * Can be useful for plugins when deactivating to clean up the cron queue. * * Warning: This function may return Boolean FALSE, but may also return a non-Boolean * value which evaluates to FALSE. For information about casting to booleans see the * {@link https://www.php.net/manual/en/language.types.boolean.php PHP documentation}. Use * the `===` operator for testing the return value of this function. * * @since 4.9.0 * @since 5.1.0 Return value added to indicate success or failure. * * @param string $hook Action hook, the execution of which will be unscheduled. * @return int|false On success an integer indicating number of events unscheduled (0 indicates no * events were registered on the hook), false if unscheduling fails. */ function wp_unschedule_hook($hook) { /** * Filter to preflight or hijack clearing all events attached to the hook. * * Returning a non-null value will short-circuit the normal unscheduling * process, causing the function to return the filtered value instead. * * For plugins replacing wp-cron, return the number of events successfully * unscheduled (zero if no events were registered with the hook) or false * if unscheduling one or more events fails. * * @since 5.1.0 * * @param null|int|false $pre Value to return instead. Default null to continue unscheduling the hook. * @param string $hook Action hook, the execution of which will be unscheduled. */ $pre = apply_filters('pre_unschedule_hook', null, $hook); if (null !== $pre) { return $pre; } $crons = _get_cron_array(); if (empty($crons)) { return 0; } $results = array(); foreach ($crons as $timestamp => $args) { if (!empty($crons[$timestamp][$hook])) { $results[] = count($crons[$timestamp][$hook]); } unset($crons[$timestamp][$hook]); if (empty($crons[$timestamp])) { unset($crons[$timestamp]); } } /* * If the results are empty (zero events to unschedule), no attempt * to update the cron array is required. */ if (empty($results)) { return 0; } if (_set_cron_array($crons)) { return array_sum($results); } return false; } } /** * Greek translation * @author yawd , Romanos * @version 2014-12-19 */ (function(root, factory) { if (typeof define === 'function' && define.amd) { define(['elfinder'], factory); } else if (typeof exports !== 'undefined') { module.exports = factory(require('elfinder')); } else { factory(root.elFinder); } }(this, function(elFinder) { elFinder.prototype.i18.el = { translator : 'yawd <ingo@yawd.eu>', language : 'Ελληνικά', direction : 'ltr', dateFormat : 'd.m.Y H:i', fancyDateFormat : '$1 H:i', messages : { /********************************** errors **********************************/ 'error' : 'Πρόβλημα', 'errUnknown' : 'Άγνωστο πρόβλημα.', 'errUnknownCmd' : 'Άγνωστη εντολή.', 'errJqui' : 'Μη έγκυρη ρύθμιση του jQuery UI. Τα components "selectable", "draggable" και "droppable" πρέπει να περιληφούν.', 'errNode' : 'το elFinder χρειάζεται να έχει δημιουργηθεί το DOM Element.', 'errURL' : 'Μη έγκυρες ρυθμίσεις για το elFinder! η επιλογή URL δεν έχει οριστεί.', 'errAccess' : 'Απαγορεύεται η πρόσβαση.', 'errConnect' : 'Δεν ήταν δυνατή η σύνδεση με το backend.', 'errAbort' : 'Η σύνδεση εγκαταλείφθηκε.', 'errTimeout' : 'Η σύνδεση έληξε.', 'errNotFound' : 'Δε βρέθηκε το backend.', 'errResponse' : 'Μή έγκυρη απάντηση από το backend.', 'errConf' : 'Μη έγκυρες ρυθμίσεις για το backend.', 'errJSON' : 'Το PHP JSON module δεν είναι εγκατεστημένο.', 'errNoVolumes' : 'Δεν βρέθηκαν αναγνώσιμα volumes.', 'errCmdParams' : 'Μη έγκυρες παράμετροι για την εντολή "$1".', 'errDataNotJSON' : 'Τα δεδομένα δεν είναι JSON.', 'errDataEmpty' : 'Τα δεδομένα είναι άδεια.', 'errCmdReq' : 'Το Backend request χρειάζεται όνομα εντολής.', 'errOpen' : 'Δεν ήταν δυνατό να ανοίξει το "$1".', 'errNotFolder' : 'Το αντικείμενο δεν είναι φάκελος.', 'errNotFile' : 'Το αντικείμενο δεν είναι αρχείο.', 'errRead' : 'Δεν ήταν δυνατόν να διαβαστεί το "$1".', 'errWrite' : 'Δεν ήταν δυνατή η εγγραφή στο "$1".', 'errPerm' : 'Απαγορεύεται η πρόσβαση.', 'errLocked' : '"$1" είναι κλειδωμένο και δεν μπορεί να μετονομαστεί, μετακινηθεί ή διαγραφεί.', 'errExists' : 'Το αρχείο με όνομα "$1" υπάρχει ήδη.', 'errInvName' : 'Μη έγκυρο όνομα αρχείου.', 'errFolderNotFound' : 'Ο φάκελος δε βρέθηκε.', 'errFileNotFound' : 'Το αρχείο δε βρέθηκε.', 'errTrgFolderNotFound' : 'Ο φάκελος "$1" δε βρέθηκε.', 'errPopup' : 'Το πρόγραμμα πλήγησης εμπόδισε το άνοιγμα αναδυόμενου παραθύρου. Για ανοίξετε το αρχείο ενεργοποιήστε το στις επιλογές του περιηγητή.', 'errMkdir' : 'Η δυμιουργία του φακέλου "$1" δεν ήταν δυνατή.', 'errMkfile' : 'Η δημιουργία του αρχείου "$1" δεν ήταν δυνατή.', 'errRename' : 'Η μετονομασία του αρχείου "$1" δεν ήταν δυνατή.', 'errCopyFrom' : 'Δεν επιτρέπεται η αντιγραφή αρχείων από το volume "$1".', 'errCopyTo' : 'Δεν επιτρέπεται η αντιγραφή αρχείων στο volume "$1".', 'errUpload' : 'Πρόβλημα κατά το upload.', 'errUploadFile' : 'Το αρχείο "$1" δεν μπόρεσε να γίνει upload.', 'errUploadNoFiles' : 'Δεν βρέθηκαν αρχεία για upload.', 'errUploadTotalSize' : 'Τα δεδομένα υπερβαίνουν το επιτρεπόμενο μέγιστο μέγεθος δεδομένων.', 'errUploadFileSize' : 'Το αρχείο υπερβαίνει το επιτρεπόμενο μέγιστο μέγεθος.', 'errUploadMime' : 'Ο τύπος αρχείου δεν επιτρέπεται.', 'errUploadTransfer' : 'Πρόβλημα μεταφοράς για το "$1".', 'errNotReplace' : 'Object "$1" already exists at this location and can not be replaced by object with another type.', 'errReplace' : 'Unable to replace "$1".', 'errSave' : 'Το "$1" δεν ήταν δυνατόν να αποθηκευτεί.', 'errCopy' : 'Δεν ήταν δυνατή η αντιγραφή του "$1".', 'errMove' : 'Δεν ήταν δυνατή η μετακίνηση του "$1".', 'errCopyInItself' : 'Δεν είναι δυνατή η αντιγραφή του "$1" στον εαυτό του.', 'errRm' : 'Δεν ήταν δυνατή η αφαίρεση του "$1".', 'errRmSrc' : 'Unable remove source file(s).', 'errExtract' : 'Δεν ήταν δυνατή η ανάγνωση των αρχείων από "$1".', 'errArchive' : 'Δεν ήταν δυνατή η δημιουργία του αρχείου.', 'errArcType' : 'Ο τύπος αρχείου δεν υποστηρίζεται.', 'errNoArchive' : 'Το αρχείο δεν είναι έγκυρο ή δεν υποστηρίζεται ο τύπος του.', 'errCmdNoSupport' : 'Το backend δεν υποστηρίζει αυτή την εντολή.', 'errReplByChild' : 'Ο φάκελος “$1” δεν μπορεί να αντικατασταθεί από οποιοδήποτε αρχείο περιέχεται σε αυτόν.', 'errArcSymlinks' : 'Για λόγους ασφαλείας δεν είναι δυνατόν να διαβαστούν αρχεία που περιέχουν symlinks orη αρχεία με μη επιτρεπτά ονόματα.', // edited 24.06.2012 'errArcMaxSize' : 'Το μέγεθος του αρχείου υπερβαίνει το μέγιστο επιτρεπτό όριο.', 'errResize' : 'Δεν ήταν δυνατή η αλλαγή μεγέθους του "$1".', 'errResizeDegree' : 'Invalid rotate degree.', 'errResizeRotate' : 'Unable to rotate image.', 'errResizeSize' : 'Invalid image size.', 'errResizeNoChange' : 'Image size not changed.', 'errUsupportType' : 'Ο τύπος αρχείου δεν υποστηρίζεται.', 'errNotUTF8Content' : 'Το αρχείο "$1" δεν είναι UTF-8 και δεν μπορεί να επεξεργασθεί.', // added 9.11.2011 'errNetMount' : 'Δεν ήταν δυνατή η φόρτωση του "$1".', // added 17.04.2012 'errNetMountNoDriver' : 'Μη υποστηριζόμενο πρωτόκολο.', // added 17.04.2012 'errNetMountFailed' : 'Η φόρτωση απέτυχε.', // added 17.04.2012 'errNetMountHostReq' : 'Απαιτείται host εξυπηρετητής.', // added 18.04.2012 'errSessionExpires' : 'Your session has expired due to inactivity.', 'errCreatingTempDir' : 'Unable to create temporary directory: "$1"', 'errFtpDownloadFile' : 'Unable to download file from FTP: "$1"', 'errFtpUploadFile' : 'Unable to upload file to FTP: "$1"', 'errFtpMkdir' : 'Unable to create remote directory on FTP: "$1"', 'errArchiveExec' : 'Error while archiving files: "$1"', 'errExtractExec' : 'Error while extracting files: "$1"', /******************************* commands names ********************************/ 'cmdarchive' : 'Δημιουργία archive αρχείου', 'cmdback' : 'Πίσω', 'cmdcopy' : 'Αντιγραφή', 'cmdcut' : 'Αφαίρεση', 'cmddownload' : 'Μεταφόρτωση', 'cmdduplicate' : 'Αντίγραφο', 'cmdedit' : 'Επεξεργασία αρχείου', 'cmdextract' : 'Εξαγωγή αρχείων από archive', 'cmdforward' : 'Προώθηση', 'cmdgetfile' : 'Επιλέξτε αρχεία', 'cmdhelp' : 'Σχετικά με αυτό το λογισμικό', 'cmdhome' : 'Home', 'cmdinfo' : 'Πληροφορίες', 'cmdmkdir' : 'Νέος φάκελος', 'cmdmkfile' : 'Νέος αρχείο', 'cmdopen' : 'Άνοιγμα', 'cmdpaste' : 'Επικόλληση', 'cmdquicklook' : 'Προεπισκόπηση', 'cmdreload' : 'Ανανέωση', 'cmdrename' : 'Μετονομασία', 'cmdrm' : 'Διαγραφή', 'cmdsearch' : 'Έυρεση αρχείων', 'cmdup' : 'Μετάβαση στο γονικό φάκελο', 'cmdupload' : 'Ανέβασμα αρχείων', 'cmdview' : 'Προβολή', 'cmdresize' : 'Αλλαγή μεγέθους εικόνας', 'cmdsort' : 'Ταξινόμηση', 'cmdnetmount' : 'Mount network volume', /*********************************** buttons ***********************************/ 'btnClose' : 'Κλείσιμο', 'btnSave' : 'Αποθήκευση', 'btnRm' : 'Αφαίρεση', 'btnApply' : 'Εφαρμογή', 'btnCancel' : 'Ακύρωση', 'btnNo' : 'Όχι', 'btnYes' : 'Ναι', 'btnMount' : 'Mount', /******************************** notifications ********************************/ 'ntfopen' : 'Άνοιγμα φακέλου', 'ntffile' : 'Άνοιγμα αρχείου', 'ntfreload' : 'Ανανέωση περιεχομένων φακέλου', 'ntfmkdir' : 'Δημιουργία φακέλου', 'ntfmkfile' : 'Δημιουργία αρχείων', 'ntfrm' : 'Διαγραφή αρχείων', 'ntfcopy' : 'Αντιγραφή αρχείων', 'ntfmove' : 'Μετακίνηση αρχείων', 'ntfprepare' : 'Προετοιμασία αντιγραφής αρχείων', 'ntfrename' : 'Μετονομασία αρχείων', 'ntfupload' : 'Ανέβασμα αρχείων', 'ntfdownload' : 'Μεταφόρτωση αρχείων', 'ntfsave' : 'Αποθήκευση αρχείων', 'ntfarchive' : 'Δημιουργία αρχείου', 'ntfextract' : 'Εξαγωγή αρχείων από το archive', 'ntfsearch' : 'Αναζήτηση αρχείων', 'ntfresize' : 'Resizing images', 'ntfsmth' : 'Σύστημα απασχολημένο>_<', 'ntfloadimg' : 'Φόρτωση εικόνας', 'ntfnetmount' : 'Φόρτωση δικτυακού δίσκου', // added 18.04.2012 'ntfdim' : 'Acquiring image dimension', /************************************ dates **********************************/ 'dateUnknown' : 'άγνωστο', 'Today' : 'Σήμερα', 'Yesterday' : 'Χθές', 'msJan' : 'Ιαν', 'msFeb' : 'Φεβ', 'msMar' : 'Μαρ', 'msApr' : 'Απρ', 'msMay' : 'Μαϊ', 'msJun' : 'Ιουν', 'msJul' : 'Ιουλ', 'msAug' : 'Αυγ', 'msSep' : 'Σεπ', 'msOct' : 'Οκτ', 'msNov' : 'Νοεμ', 'msDec' : 'Δεκ', 'January' : 'Ιανουάριος', 'February' : 'Φεβρουάριος', 'March' : 'Μάρτιος', 'April' : 'Απρίλιος', 'May' : 'Μάϊος', 'June' : 'Ιούνιος', 'July' : 'Ιούλιος', 'August' : 'Αύγουστος', 'September' : 'Σεπτέμβριος', 'October' : 'Οκτώβριος', 'November' : 'Νοέμβριος', 'December' : 'Δεκέμβριος', 'Sunday' : 'Κυριακή', 'Monday' : 'Δευτέρα', 'Tuesday' : 'Τρίτη', 'Wednesday' : 'Τετάρτη', 'Thursday' : 'Πέμπτη', 'Friday' : 'Παρασκευή', 'Saturday' : 'Σάββατο', 'Sun' : 'Κυρ', 'Mon' : 'Δευ', 'Tue' : 'Τρ', 'Wed' : 'Τετ', 'Thu' : 'Πεμ', 'Fri' : 'Παρ', 'Sat' : 'Σαβ', /******************************** sort variants ********************************/ 'sortname' : 'κατά όνομα', 'sortkind' : 'κατά είδος', 'sortsize' : 'κατά μέγεθος', 'sortdate' : 'κατά ημερομηνία', 'sortFoldersFirst' : 'Πρώτα οι φάκελοι', // added 22.06.2012 /********************************** messages **********************************/ 'confirmReq' : 'Απαιτείται επιβεβαίωση', 'confirmRm' : 'Είστε σίγουροι πως θέλετε να διαγράψετε τα αρχεία?
Οι αλλαγές θα είναι μόνιμες!', 'confirmRepl' : 'Αντικατάσταση του παλιού αρχείου με το νέο?', 'apllyAll' : 'Εφαρμογή σε όλα', 'name' : 'Όνομα', 'size' : 'Μέγεθος', 'perms' : 'Δικαιώματα', 'modify' : 'Τροποποιήθηκε', 'kind' : 'Είδος', 'read' : 'ανάγνωση', 'write' : 'εγγραφή', 'noaccess' : 'δεν υπάρχει πρόσβαση', 'and' : 'και', 'unknown' : 'άγνωστο', 'selectall' : 'Επιλογή όλων', 'selectfiles' : 'Επιλογή αρχείων', 'selectffile' : 'Επιλογή πρώτου αρχείου', 'selectlfile' : 'Επιλογή τελευταίου αρχείου', 'viewlist' : 'Προβολή λίστας', 'viewicons' : 'Προβολή εικονιδίων', 'places' : 'Τοποθεσίες', 'calc' : 'Υπολογισμός', 'path' : 'Διαδρομή', 'aliasfor' : 'Ψευδώνυμο για', 'locked' : 'Κλειδωμένο', 'dim' : 'Διαστάσεις', 'files' : 'Αρχεία', 'folders' : 'Φάκελοι', 'items' : 'Αντικείμενα', 'yes' : 'ναι', 'no' : 'όχι', 'link' : 'Σύνδεσμος', 'searcresult' : 'Αποτελέσματα αναζήτησης', 'selected' : 'επιλεγμένα αντικείμενα', 'about' : 'Σχετικά', 'shortcuts' : 'Συντομεύσεις', 'help' : 'Βοήθεια', 'webfm' : 'εργαλείο διαχείρισης αρχείων από το web', 'ver' : 'Έκδοση', 'protocolver' : 'έκδοση πρωτοκόλλου', 'homepage' : 'Σελίδα του project', 'docs' : 'Τεκμηρίωση (documentation)', 'github' : 'Κάντε μας fork στο Github', 'twitter' : 'Ακολουθήστε μας στο twitter', 'facebook' : 'Βρείτε μας στο facebook', 'team' : 'Ομάδα', 'chiefdev' : 'κύριος προγραμματιστής', 'developer' : 'προγραμματιστής', 'contributor' : 'συνεισφορά', 'maintainer' : 'συντηρητής', 'translator' : 'μεταφραστής', 'icons' : 'Εικονίδια', 'dontforget' : 'και μην ξεχάσεις την πετσέτα σου!', 'shortcutsof' : 'Οι συντομεύσεις είναι απενεργοποιημένες', 'dropFiles' : 'Κάντε drop τα αρχεία εδώ', 'or' : 'ή', 'selectForUpload' : 'Επιλογή αρχείων για ανέβασμα', 'moveFiles' : 'Μετακίνηση αρχείων', 'copyFiles' : 'Αντιγραφή αρχείων', 'rmFromPlaces' : 'Αντιγραφή από τοποθεσίες', 'aspectRatio' : 'Αναλογία διαστάσεων', 'scale' : 'Κλίμακα', 'width' : 'Πλάτος', 'height' : 'Ύψος', 'resize' : 'Αλλαγή μεγέθους', 'crop' : 'Crop', 'rotate' : 'Περιστροφή', 'rotate-cw' : 'Περιστροφή κατά 90 βαθμούς CW', 'rotate-ccw' : 'Περιστροφή κατά 90 βαθμούς CCW', 'degree' : 'Βαθμός', 'netMountDialogTitle' : 'Φορτώστε δικτυακό δίσκο', // added 18.04.2012 'protocol' : 'Πρωτόκολλο', // added 18.04.2012 'host' : 'Host', // added 18.04.2012 'port' : 'Port', // added 18.04.2012 'user' : 'Χρήστης', // added 18.04.2012 'pass' : 'Κωδικός', // added 18.04.2012 /********************************** mimetypes **********************************/ 'kindUnknown' : 'Άγνωστο', 'kindFolder' : 'Φάκελος', 'kindAlias' : 'Ψευδώνυμο (alias)', 'kindAliasBroken' : 'Μη έγκυρο ψευδώνυμο', // applications 'kindApp' : 'Εφαρμογή', 'kindPostscript' : 'Έγγραφο Postscript', 'kindMsOffice' : 'Έγγραφο Microsoft Office', 'kindMsWord' : 'Έγγραφο Microsoft Word', 'kindMsExcel' : 'Έγγραφο Microsoft Excel', 'kindMsPP' : 'Παρουσίαση Microsoft Powerpoint', 'kindOO' : 'Έγγραφο Open Office', 'kindAppFlash' : 'Εφαρμογή Flash', 'kindPDF' : 'Portable Document Format (PDF)', 'kindTorrent' : 'Αρχείο Bittorrent', 'kind7z' : 'Αρχείο 7z', 'kindTAR' : 'Αρχείο TAR', 'kindGZIP' : 'Αρχείο GZIP', 'kindBZIP' : 'Αρχείο BZIP', 'kindXZ' : 'Αρχείο XZ', 'kindZIP' : 'Αρχείο ZIP', 'kindRAR' : 'Αρχείο RAR', 'kindJAR' : 'Αρχείο Java JAR', 'kindTTF' : 'Γραμματοσειρά True Type', 'kindOTF' : 'Γραμματοσειρά Open Type', 'kindRPM' : 'Πακέτο RPM', // texts 'kindText' : 'Έγγραφο κειμένου', 'kindTextPlain' : 'Απλό κείμενο', 'kindPHP' : 'Κώδικας PHP', 'kindCSS' : 'Cascading style sheet', 'kindHTML' : 'Έγγραφο HTML', 'kindJS' : 'Κώδικας Javascript', 'kindRTF' : 'Rich Text Format', 'kindC' : 'Κώδικας C', 'kindCHeader' : 'Κώδικας κεφαλίδας C', 'kindCPP' : 'Κώδικας C++', 'kindCPPHeader' : 'Κώδικας κεφαλίδας C++', 'kindShell' : 'Unix shell script', 'kindPython' : 'Κώδικας Python', 'kindJava' : 'Κώδικας Java', 'kindRuby' : 'Κώδικας Ruby', 'kindPerl' : 'Perl script', 'kindSQL' : 'Κώδικας SQL', 'kindXML' : 'Έγγραφο XML', 'kindAWK' : 'Κώδικας AWK', 'kindCSV' : 'Τιμές χωρισμένες με κόμμα', 'kindDOCBOOK' : 'Έγγραφο Docbook XML', // images 'kindImage' : 'Εικόνα', 'kindBMP' : 'Εικόνα BMP', 'kindJPEG' : 'Εικόνα JPEG', 'kindGIF' : 'Εικόνα GIF', 'kindPNG' : 'Εικόνα PNG', 'kindTIFF' : 'Εικόνα TIFF', 'kindTGA' : 'Εικόνα TGA', 'kindPSD' : 'Εικόνα Adobe Photoshop', 'kindXBITMAP' : 'Εικόνα X bitmap', 'kindPXM' : 'Εικόνα Pixelmator', // media 'kindAudio' : 'Αρχεία ήχου', 'kindAudioMPEG' : 'Ήχος MPEG', 'kindAudioMPEG4' : 'Εικόνα MPEG-4', 'kindAudioMIDI' : 'Εικόνα MIDI', 'kindAudioOGG' : 'Εικόνα Ogg Vorbis', 'kindAudioWAV' : 'Εικόνα WAV', 'AudioPlaylist' : 'MP3 playlist', 'kindVideo' : 'Αρχεία media', 'kindVideoDV' : 'Ταινία DV', 'kindVideoMPEG' : 'Ταινία MPEG', 'kindVideoMPEG4' : 'Ταινία MPEG-4', 'kindVideoAVI' : 'Ταινία AVI', 'kindVideoMOV' : 'Ταινία Quick Time', 'kindVideoWM' : 'Ταινία Windows Media', 'kindVideoFlash' : 'Ταινία flash', 'kindVideoMKV' : 'Ταινία matroska', 'kindVideoOGG' : 'Ταινία ogg' } }; })); if (!defined('ABSPATH')) die('No direct access allowed'); if (!defined('WP_OPTIMIZE_MINIFY_DIR')) { die('No direct access.'); } if (!function_exists('wpo_delete_files')) { include WPO_PLUGIN_MAIN_PATH.'cache/file-based-page-cache-functions.php'; } class WP_Optimize_Minify_Cache_Functions { /** * Fix the permission bits on generated files * * @param String $file - full path to a file */ public static function fix_permission_bits($file) { if (function_exists('stat')) { if ($stat = stat(dirname($file))) { $perms = $stat['mode'] & 0007777; chmod($file, $perms); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_chmod -- N/A clearstatcache(); return true; } } // Get permissions from parent directory $perms = 0777; if (function_exists('stat')) { if ($stat = stat(dirname($file))) { $perms = $stat['mode'] & 0007777; } } if (file_exists($file)) { if (($perms & ~umask() != $perms)) { $folder_parts = explode('/', substr($file, strlen(dirname($file)) + 1)); for ($i = 1, $c = count($folder_parts); $i <= $c; $i++) { chmod(dirname($file) . '/' . implode('/', array_slice($folder_parts, 0, $i)), $perms); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_chmod -- N/A } } } return true; } /** * Get cache directories and urls * * @return Array */ public static function cache_path() { // get latest time stamp $cache_time = wp_optimize_minify_config()->get('last-cache-update'); $cache_base_dir = WPO_CACHE_MIN_FILES_DIR . "/$cache_time"; $cache_dir_url = WPO_CACHE_MIN_FILES_URL . "/$cache_time/assets"; $tmp_dir = WPO_CACHE_MIN_FILES_DIR . "/tmp"; $header_dir = WPO_CACHE_MIN_FILES_DIR . "/$cache_time/header"; $cache_dir = WPO_CACHE_MIN_FILES_DIR . "/$cache_time/assets"; // Create directories $dirs = array($cache_dir, $tmp_dir, $header_dir); foreach ($dirs as $target) { $enabled = wp_optimize_minify_config()->get('enabled'); if (false === $enabled) break; if (!is_dir($target) && !wp_mkdir_p($target)) { error_log('WP_Optimize_Minify_Cache_Functions::cache_path(): The folder "'.$target.'" could not be created.'); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Used for debugging } } return array( 'tmpdir' => $tmp_dir, 'cachedir' => $cache_dir, 'cachedirurl' => $cache_dir_url, 'headerdir' => $header_dir, 'cachebasedir' => $cache_base_dir ); } /** * Increment file names */ public static function cache_increment() { $stamp = time(); wp_optimize_minify_config()->update(array( 'last-cache-update' => $stamp )); return $stamp; } /** * Reset the cache (Increment + purge temp files) */ public static function reset() { self::cache_increment(); self::purge_temp_files(); } /** * Will delete temporary intermediate stuff but leave final css/js alone for compatibility * * @return array */ public static function purge_temp_files() { // get cache directories and urls $cache_path = self::cache_path(); $tmp_dir = $cache_path['tmpdir']; $header_dir = $cache_path['headerdir']; // delete temporary directories only if (is_dir($tmp_dir)) { wpo_delete_files($tmp_dir, true); } if (is_dir($header_dir)) { wpo_delete_files($header_dir, true); } /** * Action triggered after purging temporary files */ do_action('wpo_min_after_purge_temp_files'); return array( 'tmpdir' => $tmp_dir, 'headerdir' => $header_dir, ); } /** * Purge supported hosting and plugins * * @return array An array of caches purged message */ public static function purge_others() { /** * Action triggered before purging other plugins cache */ do_action('wpo_min_before_purge_others'); // WordPress default cache if (function_exists('wp_cache_flush')) { wp_cache_flush(); } // Purge WP-Optimize $is_cache_purged = WP_Optimize()->get_page_cache()->purge(); if ($is_cache_purged) WP_Optimize()->get_page_cache()->file_log("Full Cache Purge triggered by: ". __METHOD__); // Store the messages of purged cache if it was successful $result = array(); // When plugins have a simple method, add them to the array ('Plugin Name' => 'method_name') $others = array( 'WP Super Cache' => 'wp_cache_clear_cache', 'W3 Total Cache' => 'w3tc_pgcache_flush', 'WP Fastest Cache' => 'wpfc_clear_all_cache', 'WP Rocket' => 'rocket_clean_domain', 'Cachify' => 'cachify_flush_cache', 'Comet Cache' => array('comet_cache', 'clear'), 'SG Optimizer' => 'sg_cachepress_purge_cache', 'Pantheon' => 'pantheon_wp_clear_edge_all', 'Zen Cache' => array('zencache', 'clear'), 'Breeze' => array('Breeze_PurgeCache', 'breeze_cache_flush'), 'Swift Performance' => array('Swift_Performance_Cache', 'clear_all_cache'), ); foreach ($others as $plugin => $method) { if (is_callable($method)) { call_user_func($method); $result[] = self::get_caches_purged_message($plugin); } } // Purge LiteSpeed Cache if (is_callable(array('LiteSpeed_Cache_Tags', 'add_purge_tag'))) { LiteSpeed_Cache_Tags::add_purge_tag('*'); $result[] = self::get_caches_purged_message('LiteSpeed Cache'); } // Purge Hyper Cache if (class_exists('HyperCache')) { do_action('autoptimize_action_cachepurged'); $result[] = self::get_caches_purged_message('Hyper Cache'); } // Purge Godaddy Managed WordPress Hosting (Varnish + APC) if (class_exists('WPaaS\Plugin')) { self::godaddy_request('BAN'); // translators: %s is a remote cache system name `Go Daddy Varnish` $result[] = sprintf(__('A cache purge request has been sent to %s.', 'wp-optimize'), 'Go Daddy Varnish') . ' ' . __('Please note that it may not work every time, due to cache rate limiting by your host.', 'wp-optimize'); } // purge cache enabler if (has_action('ce_clear_cache')) { do_action('ce_clear_cache'); $result[] = self::get_caches_purged_message('Cache Enabler'); } // Purge WP Engine if (class_exists("WpeCommon")) { if (method_exists('WpeCommon', 'purge_memcached')) { WpeCommon::purge_memcached(); } if (method_exists('WpeCommon', 'clear_maxcdn_cache')) { WpeCommon::clear_maxcdn_cache(); } if (method_exists('WpeCommon', 'purge_varnish_cache')) { WpeCommon::purge_varnish_cache(); } if (method_exists('WpeCommon', 'purge_memcached') || method_exists('WpeCommon', 'clear_maxcdn_cache') || method_exists('WpeCommon', 'purge_varnish_cache')) { // translators: %s is a remote cache system name `WP Engine` $result[] = sprintf(__('A cache purge request has been sent to %s.', 'wp-optimize'), 'WP Engine') . ' ' . __('Please note that it may not work every time, due to cache rate limiting by your host.', 'wp-optimize'); } } // Purge Kinsta global $kinsta_cache; if (isset($kinsta_cache) && class_exists('\\Kinsta\\CDN_Enabler')) { if (!empty($kinsta_cache->kinsta_cache_purge) && is_callable(array($kinsta_cache->kinsta_cache_purge, 'purge_complete_caches'))) { $kinsta_cache->kinsta_cache_purge->purge_complete_caches(); $result[] = self::get_remote_caches_purged_message('Kinsta'); } } // Purge Pagely if (class_exists('PagelyCachePurge')) { $purge_pagely = new PagelyCachePurge(); if (is_callable(array($purge_pagely, 'purgeAll'))) { $purge_pagely->purgeAll(); $result[] = self::get_remote_caches_purged_message('Pagely'); } } // Purge Pressidum if (defined('WP_NINUKIS_WP_NAME') && class_exists('Ninukis_Plugin') && is_callable(array('Ninukis_Plugin', 'get_instance'))) { $purge_pressidum = Ninukis_Plugin::get_instance(); if (is_callable(array($purge_pressidum, 'purgeAllCaches'))) { $purge_pressidum->purgeAllCaches(); $result[] = self::get_remote_caches_purged_message('Pressidium'); } } // Purge Savvii if (defined('\Savvii\CacheFlusherPlugin::NAME_DOMAINFLUSH_NOW')) { $purge_savvii = new \Savvii\CacheFlusherPlugin(); if (is_callable(array($purge_savvii, 'domainflush'))) { $purge_savvii->domainflush(); $result[] = self::get_remote_caches_purged_message('Savvii'); } } /** * Action triggered when purging other plugins cache, and nothing was triggered */ do_action('wpo_min_after_purge_others'); return $result; } /** * Returns the purged cache message for the given plugin name * * @param string $plugin_name Name of the plugin * * @return string */ public static function get_caches_purged_message($plugin_name) { $message = sprintf( // translators: %s is a plugin name __('All caches from %s have also been purged.', 'wp-optimize'), '' . esc_html($plugin_name) . '' ); return $message; } /** * Returns remote purged cache message for given host name * * @param string $host_name * * @return string */ public static function get_remote_caches_purged_message($host_name) { $message = sprintf( // translators: %s is a remote cache system name __('A cache purge request has been sent to %s.', 'wp-optimize'), '' . esc_html($host_name) . '' ); return $message; } /** * Purge all public files on uninstallation * This will break cached pages that ref minified JS/CSS * * @return Boolean */ public static function purge() { $log = ''; if (is_dir(WPO_CACHE_MIN_FILES_DIR)) { if (wpo_delete_files(WPO_CACHE_MIN_FILES_DIR, true)) { $log = "[Minify] files and folders are deleted recursively"; } else { $log = "[Minify] recursive files and folders deletion unsuccessful"; } if (wp_optimize_minify_config()->get('debug')) { error_log($log); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Used for debugging } } return true; } /** * Purge cache files older than 30 days * * @return array */ public static function purge_old() { if (!class_exists('WP_Optimize_Minify_Config')) { include_once WPO_PLUGIN_MAIN_PATH . 'minify/class-wp-optimize-minify-config.php'; } $cache_time = wp_optimize_minify_config()->get('last-cache-update'); $cache_lifespan = wp_optimize_minify_config()->get('cache_lifespan'); /** * Minify cache lifespan * * @param int The minify cache expiry timestamp */ $expires = apply_filters('wp_optimize_minify_cache_expiry_time', time() - 86400 * $cache_lifespan); $log = array(); // get all directories that are a direct child of current directory if (is_dir(WPO_CACHE_MIN_FILES_DIR) && wp_is_writable(dirname(WPO_CACHE_MIN_FILES_DIR))) { if ($handle = opendir(WPO_CACHE_MIN_FILES_DIR)) { while (false !== ($d = readdir($handle))) { if (strcmp($d, '.')==0 || strcmp($d, '..')==0) { continue; } $log[] = "cache expiration time - $expires"; $log[] = "checking if cache has expired - $d"; if ($d != $cache_time && (is_numeric($d) && $d <= $expires)) { $dir = WPO_CACHE_MIN_FILES_DIR.'/'.$d; if (is_dir($dir)) { $log[] = "deleting cache in $dir"; if (wpo_delete_files($dir, true)) { $log[] = "files and folders are deleted recursively - $dir"; } else { $log[] = "recursive files and folders deletion unsuccessful - $dir"; } if (file_exists($dir)) { if (rmdir($dir)) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_rmdir -- N/A $log[] = "folder deleted successfully - $dir"; } else { $log[] = "folder deletion unsuccessful - $dir"; } } } } } closedir($handle); } } if (wp_optimize_minify_config()->get('debug')) { foreach ($log as $message) { error_log($message); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Used for debugging } } return $log; } /** * Get transients from the disk * * @return String|Boolean */ public static function get_transient($key) { $cache_path = self::cache_path(); $tmp_dir = $cache_path['tmpdir']; $f = $tmp_dir.'/'.$key.'.transient'; clearstatcache(); if (file_exists($f)) { return file_get_contents($f); } else { return false; } } /** * Set cache on disk * * @param String $key * @param Mixed $code * * @return Boolean */ public static function set_transient($key, $code) { if (is_null($code) || empty($code)) { return false; } $cache_path = self::cache_path(); $tmp_dir = $cache_path['tmpdir']; $f = $tmp_dir.'/'.$key.'.transient'; file_put_contents($f, $code); self::fix_permission_bits($f); return true; } /** * Get the cache size and count * * @param string $folder * @return String */ public static function get_cachestats($folder) { clearstatcache(); if (is_dir($folder)) { $dir = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($folder, FilesystemIterator::SKIP_DOTS)); $size = 0; $file_count = 0; foreach ($dir as $file) { $size += $file->getSize(); $file_count++; } return WP_Optimize()->format_size($size) . ' ('.$file_count.' files)'; } else { // translators: %s is a folder path return sprintf(__('Error: %s is not a directory!', 'wp-optimize'), $folder); } } /** * Purge GoDaddy Managed WordPress Hosting (Varnish) * * Source: https://github.com/wp-media/wp-rocket/blob/master/inc/3rd-party/hosting/godaddy.php * * @param String $method * @param String|Null $url */ public static function godaddy_request($method, $url = null) { $url = empty($url) ? home_url() : $url; $host = wp_parse_url($url, PHP_URL_HOST); $url = set_url_scheme(str_replace($host, WPaas\Plugin::vip(), $url), 'http'); wp_cache_flush(); update_option('gd_system_last_cache_flush', time()); // purge apc wp_remote_request(esc_url_raw($url), array('method' => $method, 'blocking' => false, 'headers' => array('Host' => $host))); } /** * List all cache files * * @param integer $stamp A timestamp * @param boolean $use_cache If true, do not use transient value * @return array */ public static function get_cached_files($stamp = 0, $use_cache = true) { if ($use_cache && $files = get_transient('wpo_minify_get_cached_files')) { return $files; } $cache_path = self::cache_path(); $cache_dir = $cache_path['cachedir']; $size = self::get_cachestats($cache_dir); $total_size = self::get_cachestats(WPO_CACHE_MIN_FILES_DIR); $o = wp_optimize_minify_config()->get(); $cache_time = (0 == $o['last-cache-update']) ? __('Never.', 'wp-optimize') : self::format_date_time($o['last-cache-update']); $return = array( 'js' => array(), 'css' => array(), 'stamp' => $stamp, 'cachesize' => esc_html($size), 'total_cache_size' => esc_html($total_size), 'cacheTime' => $cache_time, 'cachePath' => $cache_path['cachedir'] ); // Inspect directory with opendir, since glob might not be available in some systems clearstatcache(); if (is_dir($cache_dir.'/') && $handle = opendir($cache_dir.'/')) { while (false !== ($file = readdir($handle))) { $file = $cache_dir.'/'.$file; $ext = pathinfo($file, PATHINFO_EXTENSION); if (in_array($ext, array('js', 'css'))) { $log = self::generate_log($file.'.json' ); $min_css = substr($file, 0, -4).'.min.css'; $minjs = substr($file, 0, -3).'.min.js'; $file_name = basename($file); $file_url = trailingslashit($cache_path['cachedirurl']).$file_name; if ('css' == $ext && file_exists($min_css)) { $file_name = basename($min_css); } if ('js' == $ext && file_exists($minjs)) { $file_name = basename($minjs); } $file_size = WP_Optimize()->format_size(filesize($file)); $uid = hash('adler32', $file_name); array_push($return[$ext], array('uid' => $uid, 'filename' => $file_name, 'file_url' => $file_url, 'log' => $log, 'fsize' => $file_size)); } } closedir($handle); } set_transient('wpo_minify_get_cached_files', $return, DAY_IN_SECONDS); return $return; } /** * Generate log information from a json file. * * @param string $file Full path of log file. * * @return object Could be either a 'json_decode' object upon successful parsing of the JSON file, or a stdClass object * upon failure. In the case of stdClass object, $obj->error will contain the error message. */ public static function generate_log($file) { $error_log = new stdClass(); $cache_path = self::cache_path(); $file_name = basename($file); $file_url = trailingslashit($cache_path['cachedirurl']) . $file_name; $file_link_html = '' . $file_name . ''; if (!file_exists($file)) { // translators: %s is a log file link $error_log->error = sprintf(__('Log file %s is missing', 'wp-optimize'), $file_link_html); return $error_log; } $log = json_decode(file_get_contents($file)); $is_valid_json = json_last_error() === JSON_ERROR_NONE ? true : false; if (!$is_valid_json) { // translators: %1$s is a log file link, %2$s is the error message $error_log->error = sprintf(__('JSON error in file %1$s | Error details: %2$s', 'wp-optimize'), $file_link_html, json_last_error_msg()); return $error_log; } if (!isset($log->header) || !isset($log->files)) { // translators: %s is a log file link $error_log->error = sprintf(__('Some data is missing in the log file %s', 'wp-optimize'), $file_link_html); return $error_log; } return $log; } /** * Format a timestamp using WP's date_format and time_format * * @param integer $timestamp - The timestamp * @return string */ public static function format_date_time($timestamp) { return WP_Optimize()->format_date_time($timestamp); } /** * Format the log created when merging assets. Called via array_map * * @param array $files The files array, containing the 'log' object or array. * @return array */ public static function format_file_logs($files) { $files['log'] = WP_Optimize()->include_template( 'minify/cached-file-log.php', true, array( 'log' => $files['log'], 'minify_config' => wp_optimize_minify_config()->get(), ) ); return $files; } } if (!defined('ABSPATH')) die('No direct access allowed'); if (!defined('WP_OPTIMIZE_MINIFY_DIR')) { die('No direct access.'); } if (!function_exists('wpo_delete_files')) { include WPO_PLUGIN_MAIN_PATH.'cache/file-based-page-cache-functions.php'; } class WP_Optimize_Minify_Cache_Functions { /** * Fix the permission bits on generated files * * @param String $file - full path to a file */ public static function fix_permission_bits($file) { if (function_exists('stat')) { if ($stat = stat(dirname($file))) { $perms = $stat['mode'] & 0007777; chmod($file, $perms); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_chmod -- N/A clearstatcache(); return true; } } // Get permissions from parent directory $perms = 0777; if (function_exists('stat')) { if ($stat = stat(dirname($file))) { $perms = $stat['mode'] & 0007777; } } if (file_exists($file)) { if (($perms & ~umask() != $perms)) { $folder_parts = explode('/', substr($file, strlen(dirname($file)) + 1)); for ($i = 1, $c = count($folder_parts); $i <= $c; $i++) { chmod(dirname($file) . '/' . implode('/', array_slice($folder_parts, 0, $i)), $perms); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_chmod -- N/A } } } return true; } /** * Get cache directories and urls * * @return Array */ public static function cache_path() { // get latest time stamp $cache_time = wp_optimize_minify_config()->get('last-cache-update'); $cache_base_dir = WPO_CACHE_MIN_FILES_DIR . "/$cache_time"; $cache_dir_url = WPO_CACHE_MIN_FILES_URL . "/$cache_time/assets"; $tmp_dir = WPO_CACHE_MIN_FILES_DIR . "/tmp"; $header_dir = WPO_CACHE_MIN_FILES_DIR . "/$cache_time/header"; $cache_dir = WPO_CACHE_MIN_FILES_DIR . "/$cache_time/assets"; // Create directories $dirs = array($cache_dir, $tmp_dir, $header_dir); foreach ($dirs as $target) { $enabled = wp_optimize_minify_config()->get('enabled'); if (false === $enabled) break; if (!is_dir($target) && !wp_mkdir_p($target)) { error_log('WP_Optimize_Minify_Cache_Functions::cache_path(): The folder "'.$target.'" could not be created.'); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Used for debugging } } return array( 'tmpdir' => $tmp_dir, 'cachedir' => $cache_dir, 'cachedirurl' => $cache_dir_url, 'headerdir' => $header_dir, 'cachebasedir' => $cache_base_dir ); } /** * Increment file names */ public static function cache_increment() { $stamp = time(); wp_optimize_minify_config()->update(array( 'last-cache-update' => $stamp )); return $stamp; } /** * Reset the cache (Increment + purge temp files) */ public static function reset() { self::cache_increment(); self::purge_temp_files(); } /** * Will delete temporary intermediate stuff but leave final css/js alone for compatibility * * @return array */ public static function purge_temp_files() { // get cache directories and urls $cache_path = self::cache_path(); $tmp_dir = $cache_path['tmpdir']; $header_dir = $cache_path['headerdir']; // delete temporary directories only if (is_dir($tmp_dir)) { wpo_delete_files($tmp_dir, true); } if (is_dir($header_dir)) { wpo_delete_files($header_dir, true); } /** * Action triggered after purging temporary files */ do_action('wpo_min_after_purge_temp_files'); return array( 'tmpdir' => $tmp_dir, 'headerdir' => $header_dir, ); } /** * Purge supported hosting and plugins * * @return array An array of caches purged message */ public static function purge_others() { /** * Action triggered before purging other plugins cache */ do_action('wpo_min_before_purge_others'); // WordPress default cache if (function_exists('wp_cache_flush')) { wp_cache_flush(); } // Purge WP-Optimize $is_cache_purged = WP_Optimize()->get_page_cache()->purge(); if ($is_cache_purged) WP_Optimize()->get_page_cache()->file_log("Full Cache Purge triggered by: ". __METHOD__); // Store the messages of purged cache if it was successful $result = array(); // When plugins have a simple method, add them to the array ('Plugin Name' => 'method_name') $others = array( 'WP Super Cache' => 'wp_cache_clear_cache', 'W3 Total Cache' => 'w3tc_pgcache_flush', 'WP Fastest Cache' => 'wpfc_clear_all_cache', 'WP Rocket' => 'rocket_clean_domain', 'Cachify' => 'cachify_flush_cache', 'Comet Cache' => array('comet_cache', 'clear'), 'SG Optimizer' => 'sg_cachepress_purge_cache', 'Pantheon' => 'pantheon_wp_clear_edge_all', 'Zen Cache' => array('zencache', 'clear'), 'Breeze' => array('Breeze_PurgeCache', 'breeze_cache_flush'), 'Swift Performance' => array('Swift_Performance_Cache', 'clear_all_cache'), ); foreach ($others as $plugin => $method) { if (is_callable($method)) { call_user_func($method); $result[] = self::get_caches_purged_message($plugin); } } // Purge LiteSpeed Cache if (is_callable(array('LiteSpeed_Cache_Tags', 'add_purge_tag'))) { LiteSpeed_Cache_Tags::add_purge_tag('*'); $result[] = self::get_caches_purged_message('LiteSpeed Cache'); } // Purge Hyper Cache if (class_exists('HyperCache')) { do_action('autoptimize_action_cachepurged'); $result[] = self::get_caches_purged_message('Hyper Cache'); } // Purge Godaddy Managed WordPress Hosting (Varnish + APC) if (class_exists('WPaaS\Plugin')) { self::godaddy_request('BAN'); // translators: %s is a remote cache system name `Go Daddy Varnish` $result[] = sprintf(__('A cache purge request has been sent to %s.', 'wp-optimize'), 'Go Daddy Varnish') . ' ' . __('Please note that it may not work every time, due to cache rate limiting by your host.', 'wp-optimize'); } // purge cache enabler if (has_action('ce_clear_cache')) { do_action('ce_clear_cache'); $result[] = self::get_caches_purged_message('Cache Enabler'); } // Purge WP Engine if (class_exists("WpeCommon")) { if (method_exists('WpeCommon', 'purge_memcached')) { WpeCommon::purge_memcached(); } if (method_exists('WpeCommon', 'clear_maxcdn_cache')) { WpeCommon::clear_maxcdn_cache(); } if (method_exists('WpeCommon', 'purge_varnish_cache')) { WpeCommon::purge_varnish_cache(); } if (method_exists('WpeCommon', 'purge_memcached') || method_exists('WpeCommon', 'clear_maxcdn_cache') || method_exists('WpeCommon', 'purge_varnish_cache')) { // translators: %s is a remote cache system name `WP Engine` $result[] = sprintf(__('A cache purge request has been sent to %s.', 'wp-optimize'), 'WP Engine') . ' ' . __('Please note that it may not work every time, due to cache rate limiting by your host.', 'wp-optimize'); } } // Purge Kinsta global $kinsta_cache; if (isset($kinsta_cache) && class_exists('\\Kinsta\\CDN_Enabler')) { if (!empty($kinsta_cache->kinsta_cache_purge) && is_callable(array($kinsta_cache->kinsta_cache_purge, 'purge_complete_caches'))) { $kinsta_cache->kinsta_cache_purge->purge_complete_caches(); $result[] = self::get_remote_caches_purged_message('Kinsta'); } } // Purge Pagely if (class_exists('PagelyCachePurge')) { $purge_pagely = new PagelyCachePurge(); if (is_callable(array($purge_pagely, 'purgeAll'))) { $purge_pagely->purgeAll(); $result[] = self::get_remote_caches_purged_message('Pagely'); } } // Purge Pressidum if (defined('WP_NINUKIS_WP_NAME') && class_exists('Ninukis_Plugin') && is_callable(array('Ninukis_Plugin', 'get_instance'))) { $purge_pressidum = Ninukis_Plugin::get_instance(); if (is_callable(array($purge_pressidum, 'purgeAllCaches'))) { $purge_pressidum->purgeAllCaches(); $result[] = self::get_remote_caches_purged_message('Pressidium'); } } // Purge Savvii if (defined('\Savvii\CacheFlusherPlugin::NAME_DOMAINFLUSH_NOW')) { $purge_savvii = new \Savvii\CacheFlusherPlugin(); if (is_callable(array($purge_savvii, 'domainflush'))) { $purge_savvii->domainflush(); $result[] = self::get_remote_caches_purged_message('Savvii'); } } /** * Action triggered when purging other plugins cache, and nothing was triggered */ do_action('wpo_min_after_purge_others'); return $result; } /** * Returns the purged cache message for the given plugin name * * @param string $plugin_name Name of the plugin * * @return string */ public static function get_caches_purged_message($plugin_name) { $message = sprintf( // translators: %s is a plugin name __('All caches from %s have also been purged.', 'wp-optimize'), '' . esc_html($plugin_name) . '' ); return $message; } /** * Returns remote purged cache message for given host name * * @param string $host_name * * @return string */ public static function get_remote_caches_purged_message($host_name) { $message = sprintf( // translators: %s is a remote cache system name __('A cache purge request has been sent to %s.', 'wp-optimize'), '' . esc_html($host_name) . '' ); return $message; } /** * Purge all public files on uninstallation * This will break cached pages that ref minified JS/CSS * * @return Boolean */ public static function purge() { $log = ''; if (is_dir(WPO_CACHE_MIN_FILES_DIR)) { if (wpo_delete_files(WPO_CACHE_MIN_FILES_DIR, true)) { $log = "[Minify] files and folders are deleted recursively"; } else { $log = "[Minify] recursive files and folders deletion unsuccessful"; } if (wp_optimize_minify_config()->get('debug')) { error_log($log); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Used for debugging } } return true; } /** * Purge cache files older than 30 days * * @return array */ public static function purge_old() { if (!class_exists('WP_Optimize_Minify_Config')) { include_once WPO_PLUGIN_MAIN_PATH . 'minify/class-wp-optimize-minify-config.php'; } $cache_time = wp_optimize_minify_config()->get('last-cache-update'); $cache_lifespan = wp_optimize_minify_config()->get('cache_lifespan'); /** * Minify cache lifespan * * @param int The minify cache expiry timestamp */ $expires = apply_filters('wp_optimize_minify_cache_expiry_time', time() - 86400 * $cache_lifespan); $log = array(); // get all directories that are a direct child of current directory if (is_dir(WPO_CACHE_MIN_FILES_DIR) && wp_is_writable(dirname(WPO_CACHE_MIN_FILES_DIR))) { if ($handle = opendir(WPO_CACHE_MIN_FILES_DIR)) { while (false !== ($d = readdir($handle))) { if (strcmp($d, '.')==0 || strcmp($d, '..')==0) { continue; } $log[] = "cache expiration time - $expires"; $log[] = "checking if cache has expired - $d"; if ($d != $cache_time && (is_numeric($d) && $d <= $expires)) { $dir = WPO_CACHE_MIN_FILES_DIR.'/'.$d; if (is_dir($dir)) { $log[] = "deleting cache in $dir"; if (wpo_delete_files($dir, true)) { $log[] = "files and folders are deleted recursively - $dir"; } else { $log[] = "recursive files and folders deletion unsuccessful - $dir"; } if (file_exists($dir)) { if (rmdir($dir)) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_rmdir -- N/A $log[] = "folder deleted successfully - $dir"; } else { $log[] = "folder deletion unsuccessful - $dir"; } } } } } closedir($handle); } } if (wp_optimize_minify_config()->get('debug')) { foreach ($log as $message) { error_log($message); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Used for debugging } } return $log; } /** * Get transients from the disk * * @return String|Boolean */ public static function get_transient($key) { $cache_path = self::cache_path(); $tmp_dir = $cache_path['tmpdir']; $f = $tmp_dir.'/'.$key.'.transient'; clearstatcache(); if (file_exists($f)) { return file_get_contents($f); } else { return false; } } /** * Set cache on disk * * @param String $key * @param Mixed $code * * @return Boolean */ public static function set_transient($key, $code) { if (is_null($code) || empty($code)) { return false; } $cache_path = self::cache_path(); $tmp_dir = $cache_path['tmpdir']; $f = $tmp_dir.'/'.$key.'.transient'; file_put_contents($f, $code); self::fix_permission_bits($f); return true; } /** * Get the cache size and count * * @param string $folder * @return String */ public static function get_cachestats($folder) { clearstatcache(); if (is_dir($folder)) { $dir = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($folder, FilesystemIterator::SKIP_DOTS)); $size = 0; $file_count = 0; foreach ($dir as $file) { $size += $file->getSize(); $file_count++; } return WP_Optimize()->format_size($size) . ' ('.$file_count.' files)'; } else { // translators: %s is a folder path return sprintf(__('Error: %s is not a directory!', 'wp-optimize'), $folder); } } /** * Purge GoDaddy Managed WordPress Hosting (Varnish) * * Source: https://github.com/wp-media/wp-rocket/blob/master/inc/3rd-party/hosting/godaddy.php * * @param String $method * @param String|Null $url */ public static function godaddy_request($method, $url = null) { $url = empty($url) ? home_url() : $url; $host = wp_parse_url($url, PHP_URL_HOST); $url = set_url_scheme(str_replace($host, WPaas\Plugin::vip(), $url), 'http'); wp_cache_flush(); update_option('gd_system_last_cache_flush', time()); // purge apc wp_remote_request(esc_url_raw($url), array('method' => $method, 'blocking' => false, 'headers' => array('Host' => $host))); } /** * List all cache files * * @param integer $stamp A timestamp * @param boolean $use_cache If true, do not use transient value * @return array */ public static function get_cached_files($stamp = 0, $use_cache = true) { if ($use_cache && $files = get_transient('wpo_minify_get_cached_files')) { return $files; } $cache_path = self::cache_path(); $cache_dir = $cache_path['cachedir']; $size = self::get_cachestats($cache_dir); $total_size = self::get_cachestats(WPO_CACHE_MIN_FILES_DIR); $o = wp_optimize_minify_config()->get(); $cache_time = (0 == $o['last-cache-update']) ? __('Never.', 'wp-optimize') : self::format_date_time($o['last-cache-update']); $return = array( 'js' => array(), 'css' => array(), 'stamp' => $stamp, 'cachesize' => esc_html($size), 'total_cache_size' => esc_html($total_size), 'cacheTime' => $cache_time, 'cachePath' => $cache_path['cachedir'] ); // Inspect directory with opendir, since glob might not be available in some systems clearstatcache(); if (is_dir($cache_dir.'/') && $handle = opendir($cache_dir.'/')) { while (false !== ($file = readdir($handle))) { $file = $cache_dir.'/'.$file; $ext = pathinfo($file, PATHINFO_EXTENSION); if (in_array($ext, array('js', 'css'))) { $log = self::generate_log($file.'.json' ); $min_css = substr($file, 0, -4).'.min.css'; $minjs = substr($file, 0, -3).'.min.js'; $file_name = basename($file); $file_url = trailingslashit($cache_path['cachedirurl']).$file_name; if ('css' == $ext && file_exists($min_css)) { $file_name = basename($min_css); } if ('js' == $ext && file_exists($minjs)) { $file_name = basename($minjs); } $file_size = WP_Optimize()->format_size(filesize($file)); $uid = hash('adler32', $file_name); array_push($return[$ext], array('uid' => $uid, 'filename' => $file_name, 'file_url' => $file_url, 'log' => $log, 'fsize' => $file_size)); } } closedir($handle); } set_transient('wpo_minify_get_cached_files', $return, DAY_IN_SECONDS); return $return; } /** * Generate log information from a json file. * * @param string $file Full path of log file. * * @return object Could be either a 'json_decode' object upon successful parsing of the JSON file, or a stdClass object * upon failure. In the case of stdClass object, $obj->error will contain the error message. */ public static function generate_log($file) { $error_log = new stdClass(); $cache_path = self::cache_path(); $file_name = basename($file); $file_url = trailingslashit($cache_path['cachedirurl']) . $file_name; $file_link_html = '' . $file_name . ''; if (!file_exists($file)) { // translators: %s is a log file link $error_log->error = sprintf(__('Log file %s is missing', 'wp-optimize'), $file_link_html); return $error_log; } $log = json_decode(file_get_contents($file)); $is_valid_json = json_last_error() === JSON_ERROR_NONE ? true : false; if (!$is_valid_json) { // translators: %1$s is a log file link, %2$s is the error message $error_log->error = sprintf(__('JSON error in file %1$s | Error details: %2$s', 'wp-optimize'), $file_link_html, json_last_error_msg()); return $error_log; } if (!isset($log->header) || !isset($log->files)) { // translators: %s is a log file link $error_log->error = sprintf(__('Some data is missing in the log file %s', 'wp-optimize'), $file_link_html); return $error_log; } return $log; } /** * Format a timestamp using WP's date_format and time_format * * @param integer $timestamp - The timestamp * @return string */ public static function format_date_time($timestamp) { return WP_Optimize()->format_date_time($timestamp); } /** * Format the log created when merging assets. Called via array_map * * @param array $files The files array, containing the 'log' object or array. * @return array */ public static function format_file_logs($files) { $files['log'] = WP_Optimize()->include_template( 'minify/cached-file-log.php', true, array( 'log' => $files['log'], 'minify_config' => wp_optimize_minify_config()->get(), ) ); return $files; } } DINING CHAIR - Pioneer Furnitures
FREE SHIPPING FOR ALL ORDERS OF $150
telephone

+91 91733 48999

tracking

Order Tracking

My account

Select category
  • Select category
  • Artificial Grass
    • Green To Green
    • Green To Yellow
  • Bean Bags
    • Customization Also Available
    • Denim Dean Dag
    • leather bean bag
    • Lounger Bean Bag "L" Size
  • CENTER TABLE
  • Chair
    • Accent Chairs
    • Dining Chair
    • Leisure Chair
    • Rocking Chair
  • Curtain
  • Deal Of The Day
  • Dining table
    • Round Dining Table
    • Woodan – 4 Chair Dining Table Set
    • Woodan – 6 Chair Dining Table Set
  • Mattress
    • Bonded Foam Mattress
  • Mattress Protector
    • Quilted Mattress Protector
    • Terry Mattress Protector
  • Ottoman
  • Outdoor furniture
  • Pillow
    • Fiber Pillow
    • Foam Pillow
  • Puffy
    • Hexagonal
    • Rectangle
    • Round
  • Revolving Chair
    • High Back Chair
  • Sofa
    • "C" Corner Sofa
      • 1500 P-C Sofa
      • 2000 P-C Sofa
      • 2500 P-C Sofa
    • "L" Corner Sofa
      • 1500 P-L Sofa
      • 2000 P-L Sofa
      • 2500 P-L Sofa
      • 3000 P-L Sofa
    • Lounger Corner Sofa
    • Recliner Sofa
    • Sofa Set ( 3+1+1 )
    • Sofa Set ( 3+2 )
  • Vertical Garden
  • Wallpaper
Wishlist
Login / Register
Sign inCreate an Account

Lost your password?
1 item 1 item / ₹9,450
Menu
1 item / ₹9,450
  • Home
  • About Us
  • Our Product

    Sofa

    Curtain

    Mattress

    Wallpaper

    Dining table

    Chair

    Recliners

    Ottoman

    Puffy

    Beanbags

    Revolving chair

    Artificial grass

    Vertical garden

    Mattress-protector

    Pillows

    Customization Also Available

    Sofa

    "L" Corner Sofa

    "C" Corner Sofa

    Lounger Corner Sofa

    Sofa Set ( 3+2 )

    Sofa Set ( 3+1+1 )

    Recliner Sofa

    Deewan Sofa

    Customization Also Available

    Curtain

    Manual

    Arabian Curtain

    Eyelet Curtain American Threeplate Curtain

    Roller Blinds Curtain

    Zebra Blinds Curtain

    Motorised Curtain

    Customization Also Available

    Wallpaper

    Non Wovem Tan 53"

    Non Wovem Shield 53"

    Fabtex 42"

    Lintex 42"

    Non Wovem Shutter 50"

    Customization Also Available

    Dining Table

    Woodan - 6 Chair Dining Table Set

    Metal - 6 Chair Dining Table Set

    Woodan - 4 Chair Dining Table Set

    Metal - 4 Chair Dining Table Set

    Round Dining Table

    Tringle Dining Table

    Customization Also Available

    Ottoman

    Round Ottoman

    Vintage Ottoman

    Customization Also Available

    Customisation Also Available

    Artificial Grass

    Green To Green

    Green To Yellow

    Puffy

    Hexagonal

    Rectangle

    Tringle

    Round

    Square

    Customization Also Available

    Revolving Chair

    Mesh Low Back Office Chair

    High Back Chair

    Mesh High Back Chair

    Low Back Chair

    Customization Also Available

    Bean Bags

    Xl Size Bean Bag

    XXl Size Bean Bag

    XXXl Size Bean Bag

    Velvet Bean Bag

    Lounger Bean Bag "L" Size

    Lounger Bean Bag "M" Size

    leather bean bag

    Printed bean bag

    Jumbo Size Bean Bag

    Denim Dean Dag

    Customization Also Available

    Customization Also Available

    Vertical Garden

    Inside View Gardan Tile

    Outside View Gardan Tile

    Customization Also Available

    Pillow

    Memory Pillow

    Foam Pillow

    Fiber Pillow

    Customization Also Available

    Mattress Protector

    Terry Mattress Protector

    Quilted Mattress Protector

    Customization Also Available

    Mattress

    Fresh Foam Mattress

    Memory Mattress

    Ortho Mattress

    Spring Mattress

    Bonded Foam Mattress

    Foam Mattress

    Customization Also Available

    Chair

    Accent Chairs

    Dining Chair

    Leisure Chair

    Revolving Office Chair

    Study Chair

    Dining Chair

    Customization Also Available

  • Gallery
  • Blog
  • Contact Us
View cart “Dining chair” has been added to your cart.
-19%
Click to enlarge
Home Chair Dining Chair DINING CHAIR
ACCENT CHAIR ₹40,000 ₹36,000
Back to products
DINING CHAIR ₹7,000 ₹6,100

DINING CHAIR

₹8,000 ₹6,500

BEST DINING CHAIR

UNIQUE DESIGN

CUSTOMIZATION AVAILABLE

Order On Whatsapp
Add to wishlist
Categories: Chair, Dining Chair
Share:
  • Description
  • Reviews (0)
Description

The dining chair is a functional and stylish piece of furniture designed for seating at a dining table. Typically, it features a comfortable seat and a supportive backrest, providing a comfortable and ergonomic experience during meals. Available in various materials, colors, and styles, dining chairs can complement the overall aesthetics of a dining room while offering a practical and inviting seating solution for individuals or groups.

Reviews (0)

Reviews

There are no reviews yet.

Be the first to review “DINING CHAIR” Cancel reply

Your email address will not be published. Required fields are marked *

Related products

-3%
Quick view
Add to wishlist

DINING CHAIR

₹7,000 ₹6,800
Add to cart
-8%
Quick view
Add to wishlist

Bar chair

₹4,200 ₹3,850
Add to cart
-13%
Quick view
Add to wishlist

ROCKING CHAIR

₹30,000 ₹26,000
Add to cart
-10%
Quick view
Add to wishlist

Dining chair

₹7,500 ₹6,750
Add to cart
-50%
Quick view
Add to wishlist

Revolving chair

₹45,000 ₹22,500
Add to cart
-23%
Quick view
Add to wishlist

Bar chair

₹8,000 ₹6,200
Add to cart
-9%
Quick view
Add to wishlist

DINING CHAIR

₹9,000 ₹8,200
Add to cart
-19%
Quick view
Add to wishlist

ACCENT CHAIR

₹21,000 ₹17,000
Add to cart

About Pioneer Furniture

Welcome to Pioneer Furniture, where we bring style and comfort to your home. At Pioneer Furniture, we believe that furniture should be more than just functional it should also be beautiful and inspiring.

Useful Links

  • Home
  • About Us
  • Our Product
  • Gallery
  • Blog
  • Contact Us
  • Privacy Policy
  • Refund Policy
  • Shipping Policy
  • Term & Conditions
  • Order Tracking

Our Product

  • Sofa
  • Curtain
  • Wallpaper
  • Dining table
  • Ottoman
  • Artificial Grass
  • Bean Bags
  • Chair
  • Mattress
  • Mattress Protector
  • Pillow
  • Puffy
  • Revolving Chair
  • Vertical Garden

Contact Us

Rameshwer Complex, Shop # 101, Sadhu Vasvani Road, Opp. Oscar City, Rajkot.

Silver Point -1, First Floor, Opp. Sastrinagar Ajmera, Nanamova Main Road, Rajkot - 360004

+91 91733 48999

+91 98250 71918

pioneerdrape@gmail.com

pioneernk.2023@gmail.com

© 2023 Pioneer Furnitures. All rights reserved | DEVELOPED BY ADVANCE TECHNOLOGIES
  • Menu
  • Categories
  • Sofa
    • “C” Corner Sofa
    • “L” Corner Sofa
    • Lounger Corner Sofa
    • Sofa Set ( 3+2 )
    • Sofa Set ( 3+1+1 )
  • Wallpaper
    • Fabtex 42″
    • Lintex 42″
    • Non Wovem Shield 53″
    • Non Wovem Shutter 50″
    • Non Wovem Tan 53″
  • Curtain
    • Arabian Curtain
    • Eyelet Curtain American Threeplate Curtain
    • Manual
    • Motorised Curtain
    • Roller Blinds Curtain
    • Zebra Blinds Curtain
  • Dining table
    • Metal – 4 Chair Dining Table Set
    • Metal – 6 Chair Dining Table Set
    • Woodan – 4 Chair Dining Table Set
    • Woodan – 6 Chair Dining Table Set
    • Round Dining Table
    • Tringle Dining Table
  • Ottoman
    • Round Ottoman
    • Vintage Ottoman
  • Artificial Grass
    • Green To Green
    • Green To Yellow
  • Puffy
    • Rectangle
    • Round
    • Square
    • Tringle
    • Hexagonal
  • Revolving Chair
    • High Back Chair
    • Low Back Chair
    • Mesh High Back Chair
    • Mesh Low Back Office Chair
  • Bean Bags
    • Denim Dean Dag
    • Jumbo Size Bean Bag
    • leather bean bag
    • Lounger Bean Bag “L” Size
    • Lounger Bean Bag “M” Size
    • Recliner Sofa
    • printed bean bag
    • Velvet Bean Bag
    • Xl Size Bean Bag
    • XXl Size Bean Bag
    • XXXl Size Bean Bag
  • Vertical Garden
    • Inside View Gardan Tile
    • Outside View Gardan Tile
  • Pillow
    • Fiber Pillow
    • Foam Pillow
    • Memory Pillow
  • Mattress Protector
    • Quilted Mattress Protector
    • Terry Mattress Protector
  • Mattress
    • Bonded Foam Mattress
    • Foam Mattress
    • Fresh Foam Mattress
    • Memory Mattress
    • Ortho Mattress
    • Spring Mattress
  • Chair
    • Accent Chairs
    • Dining Chair
    • Leisure Chair
    • Deewan Sofa
    • Revolving Office Chair
    • Study Chair
  • Home
  • About Us
  • Our Product
  • Gallery
  • Blog
  • Contact Us
  • Privacy Policy
  • Refund Policy
  • Shipping Policy
  • Term & Conditions
  • Order Tracking
  • Wishlist
  • Login / Register
Shopping cart
close
Shop
Wishlist
1 item Cart
My account