$order->get_changes(); $this->persist_updates( $order ); // Update download permissions if necessary. if ( array_key_exists( 'billing_email', $changes ) || array_key_exists( 'customer_id', $changes ) ) { $data_store = \WC_Data_Store::load( 'customer-download' ); $data_store->update_user_by_order_id( $order->get_id(), $order->get_customer_id(), $order->get_billing_email() ); } // Mark user account as active. if ( array_key_exists( 'customer_id', $changes ) ) { wc_update_user_last_active( $order->get_customer_id() ); } $order->apply_changes(); $this->clear_caches( $order ); do_action( 'woocommerce_update_order', $order->get_id(), $order ); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment } /** * Proxy to udpating order meta. Here for backward compatibility reasons. * * @param \WC_Order $order Order object. * * @return void */ protected function update_post_meta( &$order ) { $this->update_order_meta( $order ); } /** * Helper method that is responsible for persisting order updates to the database. * * This is expected to be reused by other order types, and should not contain any specific metadata updates or actions. * * @param \WC_Order $order Order object. * @param bool $backfill Whether to backfill data to post tables. * * @return array $changes Array of changes. * * @throws \Exception When unable to persist order. */ protected function persist_updates( &$order, $backfill = true ) { // Fetch changes. $changes = $order->get_changes(); if ( ! isset( $changes['date_modified'] ) ) { $order->set_date_modified( time() ); } if ( $backfill ) { $this->maybe_backfill_post_record( $order ); } $this->persist_order_to_db( $order ); $order->save_meta_data(); return $changes; } /** * Helper function to decide whether to backfill post record. * * @param \WC_Abstract_Order $order Order object. * * @return void */ private function maybe_backfill_post_record( $order ) { $data_sync = wc_get_container()->get( DataSynchronizer::class ); if ( $data_sync->data_sync_is_enabled() ) { $this->backfill_post_record( $order ); } } /** * Helper method that updates post meta based on an order object. * Mostly used for backwards compatibility purposes in this datastore. * * @param \WC_Order $order Order object. * * @since 7.0.0 */ public function update_order_meta( &$order ) { $changes = $order->get_changes(); $this->update_address_index_meta( $order, $changes ); } /** * Helper function to update billing and shipping address metadata. * * @param \WC_Abstract_Order $order Order Object. * @param array $changes Array of changes. * * @return void */ private function update_address_index_meta( $order, $changes ) { // If address changed, store concatenated version to make searches faster. foreach ( array( 'billing', 'shipping' ) as $address_type ) { if ( isset( $changes[ $address_type ] ) ) { $order->update_meta_data( "_{$address_type}_address_index", implode( ' ', $order->get_address( $address_type ) ) ); } } } /** * Return array of coupon_code => meta_key for coupon which have usage limit and have tentative keys. * Pass $coupon_id if key for only one of the coupon is needed. * * @param WC_Order $order Order object. * @param int $coupon_id If passed, will return held key for that coupon. * * @return array|string Key value pair for coupon code and meta key name. If $coupon_id is passed, returns meta_key for only that coupon. */ public function get_coupon_held_keys( $order, $coupon_id = null ) { $held_keys = $order->get_meta( '_coupon_held_keys' ); if ( $coupon_id ) { return isset( $held_keys[ $coupon_id ] ) ? $held_keys[ $coupon_id ] : null; } return $held_keys; } /** * Return array of coupon_code => meta_key for coupon which have usage limit per customer and have tentative keys. * * @param WC_Order $order Order object. * @param int $coupon_id If passed, will return held key for that coupon. * * @return mixed */ public function get_coupon_held_keys_for_users( $order, $coupon_id = null ) { $held_keys_for_user = $order->get_meta( '_coupon_held_keys_for_users' ); if ( $coupon_id ) { return isset( $held_keys_for_user[ $coupon_id ] ) ? $held_keys_for_user[ $coupon_id ] : null; } return $held_keys_for_user; } /** * Add/Update list of meta keys that are currently being used by this order to hold a coupon. * This is used to figure out what all meta entries we should delete when order is cancelled/completed. * * @param WC_Order $order Order object. * @param array $held_keys Array of coupon_code => meta_key. * @param array $held_keys_for_user Array of coupon_code => meta_key for held coupon for user. * * @return mixed */ public function set_coupon_held_keys( $order, $held_keys, $held_keys_for_user ) { if ( is_array( $held_keys ) && 0 < count( $held_keys ) ) { $order->update_meta_data( '_coupon_held_keys', $held_keys ); } if ( is_array( $held_keys_for_user ) && 0 < count( $held_keys_for_user ) ) { $order->update_meta_data( '_coupon_held_keys_for_users', $held_keys_for_user ); } } /** * Release all coupons held by this order. * * @param WC_Order $order Current order object. * @param bool $save Whether to delete keys from DB right away. Could be useful to pass `false` if you are building a bulk request. */ public function release_held_coupons( $order, $save = true ) { $coupon_held_keys = $this->get_coupon_held_keys( $order ); if ( is_array( $coupon_held_keys ) ) { foreach ( $coupon_held_keys as $coupon_id => $meta_key ) { $coupon = new \WC_Coupon( $coupon_id ); $coupon->delete_meta_data( $meta_key ); $coupon->save_meta_data(); } } $order->delete_meta_data( '_coupon_held_keys' ); $coupon_held_keys_for_users = $this->get_coupon_held_keys_for_users( $order ); if ( is_array( $coupon_held_keys_for_users ) ) { foreach ( $coupon_held_keys_for_users as $coupon_id => $meta_key ) { $coupon = new \WC_Coupon( $coupon_id ); $coupon->delete_meta_data( $meta_key ); $coupon->save_meta_data(); } } $order->delete_meta_data( '_coupon_held_keys_for_users' ); if ( $save ) { $order->save_meta_data(); } } /** * Performs actual query to get orders. Uses `OrdersTableQuery` to build and generate the query. * * @param array $query_vars Query variables. * * @return array|object List of orders and count of orders. */ public function query( $query_vars ) { if ( ! isset( $query_vars['paginate'] ) || ! $query_vars['paginate'] ) { $query_vars['no_found_rows'] = true; } if ( isset( $query_vars['anonymized'] ) ) { $query_vars['meta_query'] = $query_vars['meta_query'] ?? array(); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query if ( $query_vars['anonymized'] ) { $query_vars['meta_query'][] = array( 'key' => '_anonymized', 'value' => 'yes', ); } else { $query_vars['meta_query'][] = array( 'key' => '_anonymized', 'compare' => 'NOT EXISTS', ); } } try { $query = new OrdersTableQuery( $query_vars ); } catch ( \Exception $e ) { $query = (object) array( 'orders' => array(), 'found_orders' => 0, 'max_num_pages' => 0, ); } if ( isset( $query_vars['return'] ) && 'ids' === $query_vars['return'] ) { $orders = $query->orders; } else { $orders = WC()->order_factory->get_orders( $query->orders ); } if ( isset( $query_vars['paginate'] ) && $query_vars['paginate'] ) { return (object) array( 'orders' => $orders, 'total' => $query->found_orders, 'max_num_pages' => $query->max_num_pages, ); } return $orders; } //phpcs:enable Squiz.Commenting, Generic.Commenting /** * Get the SQL needed to create all the tables needed for the custom orders table feature. * * @return string */ public function get_database_schema() { global $wpdb; $collate = $wpdb->has_cap( 'collation' ) ? $wpdb->get_charset_collate() : ''; $orders_table_name = $this->get_orders_table_name(); $addresses_table_name = $this->get_addresses_table_name(); $operational_data_table_name = $this->get_operational_data_table_name(); $meta_table = $this->get_meta_table_name(); $sql = " CREATE TABLE $orders_table_name ( id bigint(20) unsigned, status varchar(20) null, currency varchar(10) null, type varchar(20) null, tax_amount decimal(26,8) null, total_amount decimal(26,8) null, customer_id bigint(20) unsigned null, billing_email varchar(320) null, date_created_gmt datetime null, date_updated_gmt datetime null, parent_order_id bigint(20) unsigned null, payment_method varchar(100) null, payment_method_title text null, transaction_id varchar(100) null, ip_address varchar(100) null, user_agent text null, customer_note text null, PRIMARY KEY (id), KEY status (status), KEY date_created (date_created_gmt), KEY customer_id_billing_email (customer_id, billing_email), KEY billing_email (billing_email), KEY type_status (type, status), KEY parent_order_id (parent_order_id), KEY date_updated (date_updated_gmt) ) $collate; CREATE TABLE $addresses_table_name ( id bigint(20) unsigned auto_increment primary key, order_id bigint(20) unsigned NOT NULL, address_type varchar(20) null, first_name text null, last_name text null, company text null, address_1 text null, address_2 text null, city text null, state text null, postcode text null, country text null, email varchar(320) null, phone varchar(100) null, KEY order_id (order_id), UNIQUE KEY address_type_order_id (address_type, order_id), KEY email (email), KEY phone (phone) ) $collate; CREATE TABLE $operational_data_table_name ( id bigint(20) unsigned auto_increment primary key, order_id bigint(20) unsigned NULL, created_via varchar(100) NULL, woocommerce_version varchar(20) NULL, prices_include_tax tinyint(1) NULL, coupon_usages_are_counted tinyint(1) NULL, download_permission_granted tinyint(1) NULL, cart_hash varchar(100) NULL, new_order_email_sent tinyint(1) NULL, order_key varchar(100) NULL, order_stock_reduced tinyint(1) NULL, date_paid_gmt datetime NULL, date_completed_gmt datetime NULL, shipping_tax_amount decimal(26, 8) NULL, shipping_total_amount decimal(26, 8) NULL, discount_tax_amount decimal(26, 8) NULL, discount_total_amount decimal(26, 8) NULL, recorded_sales tinyint(1) NULL, UNIQUE KEY order_id (order_id), KEY order_key (order_key) ) $collate; CREATE TABLE $meta_table ( id bigint(20) unsigned auto_increment primary key, order_id bigint(20) unsigned null, meta_key varchar(255), meta_value text null, KEY meta_key_value (meta_key, meta_value(100)), KEY order_id_meta_key_meta_value (order_id, meta_key, meta_value(100)) ) $collate; "; return $sql; } /** * Returns an array of meta for an object. * * @param WC_Data $object WC_Data object. * @return array */ public function read_meta( &$object ) { $raw_meta_data = $this->data_store_meta->read_meta( $object ); return $this->filter_raw_meta_data( $object, $raw_meta_data ); } /** * Deletes meta based on meta ID. * * @param WC_Data $object WC_Data object. * @param stdClass $meta (containing at least ->id). * * @return bool */ public function delete_meta( &$object, $meta ) { $delete_meta = $this->data_store_meta->delete_meta( $object, $meta ); if ( $object instanceof WC_Abstract_Order ) { $this->maybe_backfill_post_record( $object ); } return $delete_meta; } /** * Add new piece of meta. * * @param WC_Data $object WC_Data object. * @param stdClass $meta (containing ->key and ->value). * * @return int|bool meta ID or false on failure */ public function add_meta( &$object, $meta ) { $add_meta = $this->data_store_meta->add_meta( $object, $meta ); if ( $object instanceof WC_Abstract_Order ) { $this->maybe_backfill_post_record( $object ); } return $add_meta; } /** * Update meta. * * @param WC_Data $object WC_Data object. * @param stdClass $meta (containing ->id, ->key and ->value). * * @return bool */ public function update_meta( &$object, $meta ) { $update_meta = $this->data_store_meta->update_meta( $object, $meta ); if ( $object instanceof WC_Abstract_Order ) { $this->maybe_backfill_post_record( $object ); } return $update_meta; } } community Archives - Ken's Man's Shop

Blog Archives

Haberdashery News – Late April 2024

The New Business Attire From top to bottom… Sport coats that pair with denim and 5-pocket trousers. Soft shoulders, sometimes unconstructed and other times with full canvas construction. We are seeing both patch and flap pockets, depending on the gent and his position in the company.… Read the Rest

Haberdashery News – March 2024

Prep Early for the Derby The Thomas family from last year’s house party Preparation is always the key to any successful event. Our current trunk show week with Samuelsohn is the perfect opportunity to create an outfit for the Kentucky Derby, or a house derby party.… Read the Rest

Haberdashery News – February 2024

Appreciate Love Let’s have fun celebrating Valentine’s Day! Your haberdashers brought in some extra-special gifts to get you in the right mood to enjoy Wednesday, February 14th. Here are some of our favorites so far: 2Undr Heart Briefs Dead Soxy limited edition Dallas Pegasus socks Pig & Hen Bracelets Ken’s semi-custom belts Eton dress shirts in new styles and colors A gift certificate for a custom knit shirt, to spice up the polo wardrobe A custom cologne experience A MELT Mahogany Woods candle Or you could opt for our newest blazer from Jack Victor, in blue textured lightweight stretch fabric, with a 2-button patch pocket design.… Read the Rest

Haberdashery News – January 2024

2024: The Year of Reflection and Growth As we enter our 60th year, I have been reflecting on our role in the community and in your lives. What has made Ken’s so special for the last seven decades is you. Our relationships with you.… Read the Rest

Haberdashery News – December 2023

Our Annual Book and Toy Drive Is Back! Carolina’s son Alexander assists us on his days off of school! Our annual toy and book drive for the Texas Scottish Rite Hospital for Children is back! In past years we have filled the pool table with items for these incredible children.… Read the Rest

Haberdashery News – November 2023

Are You Ready, Ladies? Starting today through November 18th, your haberdashers will be taking orders on the Fundamental Coast women’s range that we brought in exclusively for you! This is a limited-time offer on inventory that they are holding specifically for us.… Read the Rest

Haberdashery News – Late October 2023

Join Us for Our Brax Event Our Fall 2023 Brax event is coming up soon! This year we’re hosting the event during Partners Card week — our Brax representative Rene Christopher will be in the haberdashery all day on Thursday, November 2nd.… Read the Rest

Haberdashery News – October 2023

Weather Your Closet Fall may officially be here, but the weather is still warm and it’s not time to put away all of your spring and summer items just yet. Each weekend, select one category of clothing to switch out, and take the time to go over each item and make sure of a few things: Have you actually worn the items you are putting away, as well as the ones you are pulling out?… Read the Rest

Haberdashery News – September 2023

A Really Big Thank You — We Won! We officially won the 2023 Preston Hollow Advocate award for Best Men’s Clothing Store! Our little generational neighborhood haberdashery could not have done this without you and your support. We appreciate your loyalty, friendship, and most importantly the continual “modeling” of Ken’s attire throughout the metroplex.… Read the Rest

Haberdashery News – Independence Day 2023

Help Prevent Crime It is not only here, but everywhere — the haberdashers have begun to mention to our clients (whom we think of as extended family) that there has been a significant uptick in smash-and-grab robberies in Dallas. We have been hearing about it in Preston Center for months, but recently there have been occurrences here too.… Read the Rest

Haberdashery News – Father’s Day 2023

Patriarch There are many terms for a male parent: father, dad, papa, padre, daddy, and so forth. One that is not used as much anymore is “patriarch”. It does sound a bit odd to call our dads by this name, or more accurately, this title, but fathers are indeed the patriarchs of the family.… Read the Rest

Haberdashery News – June 2023

In Memory of Jim I would like to take a moment to honor my good friend and business associate, Jim Farrell. Jim was the rep for johnnie-O at our shop. Many of our clients met him either at our trunk shows, around town, or “hanging out” (a reference to the name of johnnie-O’s untuck shirts) at the shop with the haberdashers.… Read the Rest

Haberdashery News – May 2023

Faux Pas Presenting Alright, alright, alright… yes, you know this guy! I took this screenshot on my iPad while I watched Matthew McConaughey presenting an online seminar. Although the content was terrific (and similar to his book Greenlights), I kept being distracted by his outfit.… Read the Rest

Haberdashery News – Late April 2023

A Recap of Our Trunk Show Our BRAX, Wolf & Shepherd, and Beauty by Apothecary Trunk Show was this past Saturday, April 22nd. The haberdashers hosted Rene Christopher of BRAX, Mitchell Crane of Wolf & Shepherd shoes, and Suzanna Dupuy of BBA.… Read the Rest

Haberdashery News – April 2023

The Year of the Belt In our 60-year history we have seen the belt evolve from a basic necessity, to a major staple, and now a modern accessory. Today’s men are using the strap as its own statement, or to complement and enhance their ensembles.… Read the Rest

Haberdashery News – March 2023

Lone Star Horse Racing The Kentucky Derby is seven weeks away, and this year we have a couple of clients with their horses in the races! Every year the Ken’s haberdashers put together outfits for the entire Derby weekend. To do so correctly, we need time to create the desired look and match your outfit to your spouse’s, so please contact us as soon as possible.… Read the Rest

Haberdashery News – Farewell 2021

It was the fastest year ever… and we were right there with you! As we look back at 2021, we can all agree that it went by faster than any year ever! When pandemic restrictions began to lift, it felt like time was accelerating as Dallas experienced a surge of fresh energy.… Read the Rest

We Have Living Angels Amongst Us

Sometimes “thank you” is not enough Every story has a backstory. One holiday season many years back, I decided to place an advertisement in D Magazine. In lieu of promoting an item from our shop, we promoted our toy and book drive for the Texas Scottish Rite Hospital for Children.… Read the Rest

We Are Your Essential Haberdashers!

This being our 57th year in business, we understand that everyone’s situation is different than it was a year ago. Let us be a guide for you during this unsettling time. Your Ken’s team of haberdashers are more than retail and custom specialists.… Read the Rest

Ken’s Man’s Shop Celebrates 56 Years

Today we acknowledge and honor the anniversary of Ken’s Man’s Shop. Since 1964, Ken’s has been a part of the Dallas community, helping men develop and refine their personal style through clothing. From the 1960s to the 2020s, we have been here through seven decades of family, fashion, and memorable times.… Read the Rest

Father’s Day 2020

The Covid Year This recent photo was the first time I was able to see my father in person since the start of the Covid-19 lockdowns. It had been twelve weeks since our previous visit. When we could finally be in the same room together again we hugged, laughed, cried a little, laughed some more, and picked up where we left off.… Read the Rest

The Heroes Among Us

Current Heroes We have been reading and listening to the heroes among us for the past six-plus weeks. The frontline hospital doctors and nurses who fight for us daily to save our families’ and friends’ lives. The police officers and firefighters who assist us when we are stranded or in peril.… Read the Rest

Twenty-Twenty, a Clearer Vision

Twenty-twenty vision indicates that we have a clear view of what is in front of us. Our hope is that the year 2020 will bring similar clarity: being perceptive (and hopefully receptive) not only to what we see up ahead, but to everything that we can dream for our future.… Read the Rest

When Words Aren’t Enough

“Gratitude” is a word that comes up frequently during the holiday season, along with “blessings,” “family,” and “community.” This year we are especially thankful – for each and every one of our clients who continue to support us not only year after year, but also in the aftermath of the 10/20 tornado.… Read the Rest

How an F3 Tornado Can Unite a Community

It is truly amazing to see the transformation that is taking place every day at Preston and Royal in Dallas, Texas. Two weeks ago the haberdashers at Ken’s were heading to the Dallas Cowboys game, not having a clue what the next few hours would be like.… Read the Rest

Rebuilding in the Aftermath

We have been through this before. We have weathered financial crises, catastrophic global and domestic events, and natural disasters of all kinds. Our recent tornado and storm on 10/20, however, was a bit too close to home for Ken’s and the haberdashers.… Read the Rest

Partnership = Community = Paying It Forward

We know it and say it all the time in Dallas: who you know is more important than what you know. Those times of trying to get in the door to make an introduction, or searching for a contact for the business deal your company is creating.… Read the Rest