Memory Wiki

Untitled Session

2026-05-30 05:45 UTC · 48 messages · cli

You2026-05-30 05:48 UTC
Independently review the profe-sync.php WordPress mu-plugin at /var/www/html/wp-content/mu-plugins/profe-sync.php inside the Docker staging container. Check for correctness, security, edge cases, completeness, and performance. Write your review to /root/profe-gs-review-hooks.md with issues ranked by severity.
Donna2026-05-30 05:48 UTC
Tool2026-05-30 05:48 UTC
{"output": "<?php\n/**\n * Plugin Name: Profe Sync\n * Description: Sync hooks and cron jobs for the Profe ecosystem\n * Version: 1.0.0\n * Author: Nous Research\n * Network: true\n */\n\nif (!defined(\"ABSPATH\")) {\n exit;\n}\n\n/* ---------------------------------------------------------------...
Donna2026-05-30 05:48 UTC
Let me also check the PMPro source to verify property access patterns, and check what version of the schema exists.
Tool2026-05-30 05:48 UTC
{"output": "", "exit_code": 1, "error": null}
Tool2026-05-30 05:48 UTC
{"output": "not defined", "exit_code": 1, "error": null}
Donna2026-05-30 05:48 UTC
Tool2026-05-30 05:48 UTC
{"output": "/var/www/html/wp-content/plugins/paid-memberships-pro/classes/class.memberorder.php", "exit_code": 0, "error": null}
Tool2026-05-30 05:48 UTC
{"output": "Field\tType\tNull\tKey\tDefault\tExtra\nid\tbigint(20) unsigned\tNO\tPRI\tNULL\tauto_increment\nuuid\tchar(36)\tNO\tUNI\tNULL\t\nuser_login\tvarchar(100)\tNO\tUNI\tNULL\t\nuser_pass\tvarchar(255)\tNO\t\t\t\nuser_email\tvarchar(100)\tNO\tUNI\tNULL\t\nuser_url\tvarchar(200)\tNO\t\t\t\nuser...
Donna2026-05-30 05:48 UTC
Tool2026-05-30 05:48 UTC
{"output": "362:\t\t\t\t\t_doing_it_wrong( __METHOD__, esc_html__( 'PaymentAmount is deprecated. Get billing_amount from $this->getMembershipLevelAtCheckout() instead.', 'paid-memberships-pro' ), '3.2' );\n364:\t\t\t\t\treturn empty( $level->billing_amount ) ? 0 : $level->billing_amount;\n390:\t\t\t...
Tool2026-05-30 05:48 UTC
{"output": "40:function profe_get_uuid_for_wp_user($wp_user_id) {\n41: $uuid = get_user_meta($wp_user_id, \"profe_uuid\", true);\n49: update_user_meta($wp_user_id, \"profe_uuid\", $uuid);\n78: * Helper: split display_name into first/last\n81:function profe_split_display_name($display_name) {\n...
Donna2026-05-30 05:48 UTC
Tool2026-05-30 05:48 UTC
{"output": "269:\t\tfunction __construct($id = NULL)", "exit_code": 0, "error": null}
Tool2026-05-30 05:48 UTC
{"output": "802:\t\t\t\t$this->billing->name = $dbobj->billing_name;\n803:\t\t\t\t$this->billing->street = $dbobj->billing_street;\n804:\t\t\t\t$this->billing->street2 = $dbobj->billing_street2;\n805:\t\t\t\t$this->billing->city = $dbobj->billing_city;\n806:\t\t\t\t$this->billing->state = $dbobj->bi...
Donna2026-05-30 05:48 UTC
Tool2026-05-30 05:48 UTC
{"output": "29:\t\tprivate $user_id = 0;\n415:\t\t\t\t\t$user = get_userdata( $this->user_id );\n598:\t\t\tif ( isset( $args['user_id'] ) ) {\n599:\t\t\t\tif ( ! is_array( $args['user_id'] ) ) {\n600:\t\t\t\t\t$where[] = '`o`.`user_id` = %d';\n601:\t\t\t\t\t$prepared[] = $args['user_id'];\n603:\t...
Donna2026-05-30 05:48 UTC
Tool2026-05-30 05:48 UTC
{"output": "", "exit_code": 0, "error": null}
Tool2026-05-30 05:48 UTC
{"output": "1384:\t\t\t\tdo_action('pmpro_updated_order', $this);\n1625:\t\t\t\tdo_action('pmpro_updated_order', $this);\n/var/www/html/wp-content/plugins/paid-memberships-pro/includes/checkout.php:275:\t\t\tdo_action_deprecated( 'pmpro_discount_code_used', array( $discount_code_id, $order->user_id,...
Donna2026-05-30 05:48 UTC
Tool2026-05-30 05:48 UTC
{"output": "/var/www/html/wp-content/plugins/paid-memberships-pro/includes/checkout.php:275:\t\t\tdo_action_deprecated( 'pmpro_discount_code_used', array( $discount_code_id, $order->user_id, $order->id ), '3.3.2', 'pmpro_added_order' );\n/var/www/html/wp-content/plugins/paid-memberships-pro/includes...
Donna2026-05-30 05:48 UTC
Tool2026-05-30 05:48 UTC
{"output": "//set up actions\n\t\t\t\t$before_action = \"pmpro_add_order\";\n\t\t\t\t$after_action = \"pmpro_added_order\";\n\t\t\t\t\n\t\t\t\t//only on inserts, we might want to set the expirationmonth and expirationyear from ExpirationDate/\n\t\t\t\t// This will be removed in a future version.\n\t...
Donna2026-05-30 05:48 UTC
Tool2026-05-30 05:48 UTC
{"output": "1536:\t\t\t\tdo_action($after_action, $this);", "exit_code": 0, "error": null}
Donna2026-05-30 05:48 UTC
Tool2026-05-30 05:48 UTC
{"output": "", "exit_code": 1, "error": null}
Donna2026-05-30 05:48 UTC
Tool2026-05-30 05:48 UTC
{"output": "/var/www/html/wp-content/plugins/paid-memberships-pro/includes/lib/wp-fusion/class-pmpro.php:623:\t\tif ( did_action( 'pmpro_before_change_membership_level' ) && ! did_action( 'pmpro_after_change_membership_level' ) ) {\n/var/www/html/wp-content/plugins/paid-memberships-pro/includes/lib/...
Tool2026-05-30 05:48 UTC
{"output": "", "exit_code": 0, "error": null}
Donna2026-05-30 05:48 UTC
Tool2026-05-30 05:48 UTC
{"output": "1109:\t\tdo_action( 'pmpro_after_change_membership_level', 0, $user_id, $level_id );\n1225:\t * or pmpro_after_change_membership_level later to run your own deactivation logic.\n1354:\tdo_action( 'pmpro_after_change_membership_level', $level_id, $user_id, null );", "exit_code": 0, "error...
Donna2026-05-30 05:48 UTC
Tool2026-05-30 05:48 UTC
{"output": "pmpro_clear_level_cache_for_user( $user_id );\n\n\t/**\n\t * Action to run after the membership level changes.\n\t *\n\t * @param int $level_id ID of the level changed to.\n\t * @param int $user_id ID of the user changed.\n\t * @param int $cancel_level ID of the level being cancelled if ...
Donna2026-05-30 05:48 UTC
Tool2026-05-30 05:48 UTC
{"output": "316:\t\tpublic function __get( $property ) {\n439:\t\tpublic function __set( $property, $value ) {\n484:\t\tpublic function __isset( $property ) {", "exit_code": 0, "error": null}
Donna2026-05-30 05:48 UTC
Tool2026-05-30 05:48 UTC
{"output": "public function __get( $property ) {\n\t\t\t/**\n\t\t\t * Special case. We want to add `discount_code_id` as a property/db column in the future.\n\t\t\t * For now, we should support `discount_code_id` as a \"property\" by adding it here and\n\t\t\t * querying the pmpro_discount_codes_use...
Donna2026-05-30 05:48 UTC
Tool2026-05-30 05:48 UTC
{"output": "public function __isset( $property ) {\n\n\t\t\treturn property_exists( $this, $property ) || isset( $this->other_properties[ $property ] );\n\t\n\t\t}\n\n\t\t/**\n\t\t * Unset Magic Method.\n\t\t *\n\t\t * @since 2.9.1\n\t\t * \n\t\t * @param string $property The property we want to uns...
Donna2026-05-30 05:48 UTC
Tool2026-05-30 05:48 UTC
{"output": "$dbobj = $wpdb->get_row( $wpdb->prepare( \"SELECT * FROM $wpdb->pmpro_membership_orders WHERE id = %d LIMIT 1\", $id ) );\n\n\t\t\tif($dbobj)\n\t\t\t{\n\t\t\t\t$this->id = $dbobj->id;\n\t\t\t\t$this->code = $dbobj->code;\n\t\t\t\t$this->session_id = $dbobj->session_id;\n\t\t\t\t$this->us...
Donna2026-05-30 05:48 UTC
Tool2026-05-30 05:48 UTC
{"output": "/**\n\t\t\t\t * Special case. We want to add `discount_code_id` as a property/db column in the future.\n\t\t\t\t * For now, if we are saving an order with a non-null discount_code_id property,\n\t\t\t\t * call updateDiscountCode to save the discount code use in the current pmpro_discount...
Donna2026-05-30 05:48 UTC
Now I have all the information I need. Let me write the comprehensive review.
Tool2026-05-30 05:48 UTC
{"bytes_written": 15566, "dirs_created": true, "lint": {"status": "skipped", "message": "No linter for .md files"}}
Donna2026-05-30 05:48 UTC
## Summary **What I did:** - Extracted and analyzed `profe-sync.php` from the Docker staging container - Audited the PMPro `MemberOrder` class source code to verify property access patterns (magic methods `__get`, `__isset`, billing data structure, user_id visibility) - Retrieved the actual `profe_users` table schema from `profe_main` database - Verified all 14 columns and cross-referenced against the sync code - Checked hook signatures against the actual WordPress/PMPro/BP `do_action()` calls - Wrote a comprehensive review to `/root/profe-gs-review-hooks.md` **What I found — 11 issues, verdict: FAIL:** - **2 CRITICAL:** 1. **Billing geo hooks completely broken** — PMPro stores billing at `$order->billing->city`, not `$order->billing_city`. Both `pmpro_added_order` and `pmpro_updated_order` silently never sync. 2. **Password hash leaked to external DB** — `$user->user_pass` stored in `profe_users`, expanding the attack surface unnecessarily. - **2 HIGH:** 3. BP XProfile cron fetches ALL rows for ALL users in one unbounded query — memory exhaustion risk at scale. 4. Billing geo cleanup cron fetches ALL successful orders with no LIMIT. - **5 MEDIUM:** Missing UPSERT in `profile_update` (non-self-healing), hardcoded XProfile field names, 3 unsynced columns (`user_url`, `user_activation_key`, `user_status`), cron scheduling only on `wp` action, unicode whitespace not handled in name splitting. - **2 LOW:** Redundant require_once, missing diagnostic logging. **File created:** `/root/profe-gs-review-hooks.md` (15.5 KB, full markdown review with issue ranking, fix recommendations, and completeness checklist)