New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Render order edit page #33638
Render order edit page #33638
Conversation
a3031de
to
cffddd9
Compare
plugins/woocommerce/includes/admin/meta-boxes/class-wc-meta-box-order-downloads.php
Outdated
Show resolved
Hide resolved
plugins/woocommerce/src/Internal/Admin/Orders/MetaBoxes/CustomMetaBox.php
Outdated
Show resolved
Hide resolved
There is a minor different with the meta box title at the top of the editor page:
"Order" is missing before the order ID. I don't think this matters a lot, in fact I think this is a little cleaner, but flagging it as:
|
This is looking great, nice work. I left some comments above (mostly minor), but still need to perform some more testing relating to the existing order editor. |
Porting some extensions that integrate with the existing order editor to this new COT order seemed straightforward; one minor detail is custom meta boxes with Now they render below it—but since meta boxes are user orderable in any case, and since most extensions will anyway require a couple of tweaks to integrate with the new editor, I don't think we really need to change anything. |
26d5de5
to
725fe84
Compare
Test Results SummaryCommit SHA: b0f491d
To view the full E2E test report, click here. To view all test reports, visit the WooCommerce Test Reports Dashboard. |
This does look like a backward compatibility issue, I have added an issue to track a fix here #33767
Where do I see these options from? For me, there is just a |
That's the right spot, but there should also be a
Edit: nope, I'm wrong. On testing the latest changes I don't see it within the COT editor (but I do see it in the CPT editor). Should we add it, or, log as a follow-up issue perhaps? |
<?php do_meta_boxes( $this->screen_id, 'side', $this->order ); ?> | ||
</div> | ||
<div id="postbox-container-2" class="postbox-container"> | ||
<?php | ||
do_meta_boxes( $this->screen_id, 'normal', $this->order ); | ||
do_meta_boxes( $this->screen_id, 'advanced', $this->order ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An interesting thing: we are passing an order object to do_meta_boxes()
here whereas, in the legacy editor, do_meta_boxes()
receives WP_Post
objects instead.
Execution proceeds from do_meta_boxes()
along to WC_Meta_Box_Order_Actions::output()
and this method interacts with what it thinks is a post object, and tries to access post object properties directly.
Everything still mostly works (though, I'm really only testing the rendering of course) but unfortunately it results in a lot of notices being generated since some of the properties that exist for WP_Post
objects don't exist for order objects and, even where there is overlap, direct access to properties is a no-no for orders and results in doing-it-wrong notices.
In my testing, I see 39 notice-level errors (related to this issue) being emitted each time the editor is loaded. Apologies for not spotting this on my earlier pass.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good!
Two remaining items from my perspective:
- A lot of doing-it-wrong and getting-property-of-non-object notices (see this note)
- Unsure if we want to tackle adding the Screen Options pulldown in this PR, or separately (see this note)
Note that I am working on adding a compatibility file that will have a bunch of corresponding functions for files containing equivalent |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good: provisionally hitting approve, then (I'm not completely clear if you are planning to tackle those things through a different PR or PRs, but if so this is at a good point to merge) 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks good, but I hereby request a change for the sake of code maintainability.
5e5b1c1
to
e671a2a
Compare
/** | ||
* A class of utilities for dealing with orders. | ||
*/ | ||
final class OrderUtil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for adding this. However (sorry I know it's more work) I think that methods shouldn't be static, instead the class should be registered in the container and the instance should be retrieved using wc_get_container
(or declared as an argument of the init
method in classes using it).
The reason for this is testability: it's very easy to replace a class with a mock in unit tests if the class has been registered in the container, but mocking static methods requires the usage of the Code Hacker which is an ugly workaround reserved for legacy code. Yes we have utility classes with static methods (e.g. ArrayUtil
) but in these cases the methods are idempotent: the output depends exclusively on the input (no shared/global state involded) so there's really nothing to mock.
Also this is not an Internal
class so we can't play the "we'll modify it later" card in this case. 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case, there is no shared state as well. If you are referring to the global theorder
then see my next comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant "shared state" in a generic sense, as in "anything that is not strictly the arguments passed to the method". In this case, the result of the methods of the class depend on the database state in various ways.
Let me illustrate my concern about testability with an example. Imagine that we are testing a second class that calls OrderUtil::get_post_or_object_meta($some_post)
, and we want to verify that the tested class behaves differently depending on whether the passed post has a given meta key or not:
- If
get_post_or_object_meta
is static, in order to setup the test we need to either actually introduce some meta values in the database (cumbersome) or patch the static method with the code hacker (not ideal, this should only be needed for legacy code). - But if
get_post_or_object_meta
is a regular instance method, and the tested class doeswc_get_container()->get(OrderUtil::class)->get_post_or_object_meta($some_post)
instead, then in the test we can easily replace the instance ofOrderUtil
with a mock that directly returns whatever we want (especially since we introduced theDynamicDecorator
class).
I realize that static methods are easier to use, and especially for external contributors being able to just e.g. OrderUtil::custom_orders_table_usage_is_enabled()
would be very conveniet. But this is something to be considered and solved separately (e.g. by adding a second static version of the method, or adding a proxy class with static methods of the class, or something of that style).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see thanks, I have updated by adding instance
method of these functions in a8d4a7f. Note that custom_orders_table_usage_is_enabled
is not instansicized
as it is already a static proxy for an instance method.
* @return WC_Order WC_Order object. | ||
*/ | ||
public static function init_theorder_object( $post_or_order_object ) : WC_Order { | ||
global $theorder; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should avoid introducing new global objects, for maintainability and testing purposes. I suggest replacing this one with a pair of set_current_order
and get_current_order
methods in the OrderUtil
object (which, as per my previous comment, would be a shared instance registered in the container); the order object itself would be stored as a private property in the OrderUtil
instance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not a new object, if you see the usages, this object is already defined by the callee function. This method only helps in initialising by either a Post or an Order object, but when it's called global $theorder
is already being used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I get it. But anyway, global objects still make things difficult to test.
So I wonder if we could kind of "soft deprecate" the global variable by encapsulating it in a pair of set_current_order
and get_current_order
methods, and start using those ourselves (instead of directly the global object) for any new code, thus encouraging others to do the same.
In that case, this method can stay as is, but perhpas it could be renamed to init_current_order
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with your point about soft deprecating theorder
, but I don't think it should be part of this PR. It's going to need much intentional and careful approach, rather than doing it in an unrelated PR.
Hi @vedanshujain, thanks for merging this pull request. Please take a look at these follow-up tasks you may need to perform:
|
* Implement order edit screen rendering. * Add changelog. * Use global function instead of harcoded string. * Use pagecontroller to display order edit form. * Move HTML out from the translatable string. Co-authored-by: Barry Hughes <3594411+barryhughes@users.noreply.github.com> * Capitalize `Order` for consistency. Co-authored-by: Barry Hughes <3594411+barryhughes@users.noreply.github.com> * Minor realignment. * phpcs fix . * Decouple meta boxes from global $post object to support custom order tables. * Bug fixes - improperly set $order object, and allow passing null. * Make order item meta work with order object. * Use `$order` object to minimize diff. * Refactor $theorder object initialization to a common method. * Remove check for WC_Order object. * Move common methods to inside `src` in a dedicated class. * Fix spacing for code style. * Renamed method to be more accurate. * Add proxies for static so they can be mocked. * Remove PageController import. * Move helper methods to an internal util class. Co-authored-by: Barry Hughes <3594411+barryhughes@users.noreply.github.com>
All Submissions:
Changes proposed in this Pull Request:
Implements an order edit screen which is based on the WP's default post edit screen. With COT, we can't use the default post edit screen since it needs a post object to work properly. This PR implements a lightweight version of
edit-form-advanced.php
with reusing code as much as possible.Existing order meta boxes are also modified to work with both orders and post objects.
Note that this only implements rendering, saving an order will not work just with this PR.
Closes #32471 .
How to test the changes in this Pull Request:
Note that since this uses a lot of current code with some changes, it's also necessary to test out the current order edit screen. To do that:
Known issue
Other information:
pnpm changelog add --filter=<project>
?FOR PR REVIEWER ONLY: