diff --git a/ajax/memberships/users/getList.php b/ajax/memberships/users/getList.php
index 8fef82676455197b839e2762ca4ba970f968542c..ec0d11f22c375c36f35e2e79941bd61465201304 100644
--- a/ajax/memberships/users/getList.php
+++ b/ajax/memberships/users/getList.php
@@ -22,6 +22,8 @@ function ($membershipId, $searchParams) {
         $Membership      = $Memberships->getChild((int)$membershipId);
         $membershipUsers = array();
 
+//        $Membership->addUser(QUI::getUserBySession());
+
         foreach ($Membership->searchUsers($searchParams) as $membershipUserId) {
             /** @var MembershipUser $MembershipUser */
             $MembershipUser    = $MembershipUsers->getChild($membershipUserId);
diff --git a/bin/controls/profile/UserProfile.Membership.html b/bin/controls/profile/UserProfile.Membership.html
index ce4177d95cffa216c476e7680d549dc7cabc34ce..d97efc285ffcf959717e7e00fda9a539c88e01f4 100644
--- a/bin/controls/profile/UserProfile.Membership.html
+++ b/bin/controls/profile/UserProfile.Membership.html
@@ -1,34 +1,42 @@
-<div class="quiqqer-memberships-profile-userprofile-membership-info grid-50">
-    <h2 class="quiqqer-memberships-profile-userprofile-membership-info-title">
-        {{membershipTitle}}
-    </h2>
-    <p>
-        {{membershipShort}}
-    </p>
-</div>
-<div class="quiqqer-memberships-profile-userprofile-membership-status-container grid-50 grid-parent">
-    <div class="grid-100">
-        <div class="grid-60">
-            {{labelAddedDate}}
+<section class="quiqqer-memberships-profile-userprofile-membership">
+
+    <header class="quiqqer-memberships-profile-userprofile-membership-header">
+        <div class="quiqqer-memberships-profile-userprofile-membership-header-title">
+            <h3>
+                {{membershipTitle}}
+            </h3>
         </div>
-        <div class="grid-40">
-            {{addedDate}}
+        <div class="quiqqer-memberships-profile-userprofile-membership-header-short">
+            <span>{{membershipShort}}</span>
+            <div class="quiqqer-memberships-profile-userprofile-membership-header-info"></div>
         </div>
-    </div>
-    <div class="grid-100">
-        <div class="grid-60">
-            {{labelEndDate}}
+    </header>
+
+    <div class="quiqqer-memberships-profile-userprofile-membership-body">
+        <div class="quiqqer-memberships-profile-userprofile-membership-body-entry">
+            <div class="quiqqer-memberships-profile-userprofile-membership-body-entry-label">
+                {{labelAddedDate}}
+            </div>
+            <div class="quiqqer-memberships-profile-userprofile-membership-body-entry-value">
+                {{addedDate}}
+            </div>
         </div>
-        <div class="grid-40">
-            {{endDate}}
+        <div class="quiqqer-memberships-profile-userprofile-membership-body-entry">
+            <div class="quiqqer-memberships-profile-userprofile-membership-body-entry-label">
+                {{labelEndDate}}
+            </div>
+            <div class="quiqqer-memberships-profile-userprofile-membership-body-entry-value">
+                {{endDate}}
+            </div>
         </div>
-    </div>
-    <div class="grid-100">
-        <div class="grid-60">
-            {{labelStatus}}
+        <div class="quiqqer-memberships-profile-userprofile-membership-body-entry">
+            <div class="quiqqer-memberships-profile-userprofile-membership-body-entry-label">
+                {{labelStatus}}
+            </div>
+            <div class="quiqqer-memberships-profile-userprofile-membership-body-entry-value quiqqer-memberships-profile-userprofile-status"></div>
+            <div class="quiqqer-memberships-profile-userprofile-status-modifier"></div>
         </div>
-        <div class="quiqqer-memberships-profile-userprofile-status grid-40"></div>
+        <div class="quiqqer-memberships-profile-userprofile-btn"></div>
     </div>
-    <div class="quiqqer-memberships-profile-userprofile-status-modifier grid-100"></div>
-    <div class="quiqqer-memberships-profile-userprofile-btn grid-100"></div>
-</div>
\ No newline at end of file
+
+</section>
\ No newline at end of file
diff --git a/bin/controls/profile/UserProfile.css b/bin/controls/profile/UserProfile.css
index 3b2edd0182d782dc643097853737dfd3ac255e0f..be7faa6a3622398e726fa693aca6998ddccae699 100644
--- a/bin/controls/profile/UserProfile.css
+++ b/bin/controls/profile/UserProfile.css
@@ -1,25 +1,66 @@
+.quiqqer-memberships-profile-userprofile-info-header {
+    margin: 0 0 10px 0;
+}
+
 .quiqqer-memberships-profile-userprofile-membership {
+    border: 1px #ddd solid;
+    clear: both;
     float: left;
+    margin-bottom: 20px;
     width: 100%;
 }
 
-.quiqqer-memberships-profile-userprofile-membership:not(:last-of-type) {
-    margin-bottom: 20px;
+/*****************
+ * Header
+ *****************/
+.quiqqer-memberships-profile-userprofile-membership-header {
+    background: #f6f6f6;
+    border-bottom: 1px #ddd solid;
+    float: left;
+    padding: 10px;
+    width: 100%;
+}
+
+.quiqqer-memberships-profile-userprofile-membership-header-title h3 {
+    margin: 0 0 5px 0;
 }
 
-.quiqqer-memberships-profile-userprofile-membership-info-content:hover {
+.quiqqer-memberships-profile-userprofile-membership-header-info-icon:hover {
     cursor: pointer;
     opacity: 0.7;
 }
 
-.quiqqer-memberships-profile-userprofile-membership-info-content {
-    float: right;
-    font-size: 20px;
+.quiqqer-memberships-profile-userprofile-membership-header-info {
+    display: inline-block;
+}
+
+/*****************
+ * Body
+ *****************/
+.quiqqer-memberships-profile-userprofile-membership-body {
+    float: left;
+    padding: 10px;
+    width: 100%;
+}
+
+.quiqqer-memberships-profile-userprofile-membership-body-entry {
+    clear: both;
+    float: left;
+    width: 100%;
+}
+
+.quiqqer-memberships-profile-userprofile-membership-body-entry-label {
+    float: left;
+    min-width: 200px;
+}
+
+.quiqqer-memberships-profile-userprofile-membership-body-entry-value {
+    float: left;
 }
 
 .quiqqer-memberships-profile-userprofile-status-modifier {
-    font-size: 14px;
-    text-align: center;
+    float: left;
+    padding-left: 5px;
 }
 
 .quiqqer-memberships-profile-userprofile-status-cancelled {
@@ -34,9 +75,30 @@
     color: #008000;
 }
 
+.quiqqer-memberships-profile-userprofile-btn {
+    float: left;
+    width: 100%;
+    margin-top: 10px;
+}
+
 .quiqqer-memberships-profile-userprofile-btn .qui-button {
-    border: 1px solid #ff0000 !important;
     float: right;
-    font-size: 12px;
-    line-height: 20px;
+}
+
+@media (max-width: 768px) {
+    .quiqqer-memberships-profile-userprofile-membership-body-entry-label {
+        width: 100%;
+    }
+
+    .quiqqer-memberships-profile-userprofile-membership-body-entry {
+        margin-bottom: 10px;
+    }
+
+    .quiqqer-memberships-profile-userprofile-status-modifier {
+        padding: 0;
+    }
+
+    .quiqqer-memberships-profile-userprofile-btn .qui-button {
+        width: 100%;
+    }
 }
diff --git a/bin/controls/profile/UserProfile.html b/bin/controls/profile/UserProfile.html
index 654b9925df1a38ab4125d8b9c15e265fa614cba1..aa8312c0349677ee36802b5c0f161a101dd2ea96 100644
--- a/bin/controls/profile/UserProfile.html
+++ b/bin/controls/profile/UserProfile.html
@@ -1,3 +1,3 @@
-<h1>{{header}}</h1>
+<h2 class="quiqqer-memberships-profile-userprofile-info-header">{{header}}</h2>
 <p class="quiqqer-memberships-profile-userprofile-info"></p>
-<div class="quiqqer-memberships-profile-userprofile-memberships grid-parent"></div>
\ No newline at end of file
+<div class="quiqqer-memberships-profile-userprofile-memberships-container"></div>
\ No newline at end of file
diff --git a/bin/controls/profile/UserProfile.js b/bin/controls/profile/UserProfile.js
index 0ac9a6cbc0d005db014e00b1655e7cf6da8cb6be..3fd776120cd2d58cdef941a2254a12e11db10735 100644
--- a/bin/controls/profile/UserProfile.js
+++ b/bin/controls/profile/UserProfile.js
@@ -5,18 +5,6 @@
  *
  * @module package/quiqqer/memberships/bin/controls/profile/UserProfile
  * @author www.pcsg.de (Patrick Müller)
- *
- * @require qui/controls/Control
- * @require qui/controls/loader/Loader
- * @require qui/controls/windows/Confirm
- * @require qui/controls/buttons/Button
- * @require package/quiqqer/memberships/bin/MembershipUsers
- * @require Locale
- * @require Ajax
- * @require Mustache
- * @require text!package/quiqqer/memberships/bin/controls/profile/UserProfile.html
- * @require text!package/quiqqer/memberships/bin/controls/profile/UserProfile.MembershipStatus.html
- * @require css!package/quiqqer/memberships/bin/controls/profile/UserProfile.css
  */
 define('package/quiqqer/memberships/bin/controls/profile/UserProfile', [
 
@@ -48,7 +36,7 @@ define('package/quiqqer/memberships/bin/controls/profile/UserProfile', [
         Type   : 'package/quiqqer/memberships/bin/controls/profile/UserProfile',
 
         Binds: [
-            '$onInject',
+            '$onImport',
             'refresh',
             '$build',
             '$openCancelConfirm',
@@ -67,14 +55,14 @@ define('package/quiqqer/memberships/bin/controls/profile/UserProfile', [
             this.$memberships = [];
 
             this.addEvents({
-                onInject: this.$onInject
+                onImport: this.$onImport
             });
         },
 
         /**
          * Event: onImport
          */
-        $onInject: function () {
+        $onImport: function () {
             this.$Elm.addClass('quiqqer-memberships-membershipusersarchive');
 
             var lgPrefix = 'controls.profile.userprofile.template.';
@@ -110,7 +98,7 @@ define('package/quiqqer/memberships/bin/controls/profile/UserProfile', [
          */
         $build: function () {
             var MembershipsElm = this.$Elm.getElement(
-                '.quiqqer-memberships-profile-userprofile-memberships'
+                '.quiqqer-memberships-profile-userprofile-memberships-container'
             );
 
             MembershipsElm.set('html', '');
@@ -173,15 +161,14 @@ define('package/quiqqer/memberships/bin/controls/profile/UserProfile', [
             }
 
             var MembershipElm = new Element('div', {
-                'class': 'quiqqer-memberships-profile-userprofile-membership grid-100',
-                html   : Mustache.render(membershipTemplate, {
+                html: Mustache.render(membershipTemplate, {
                     membershipTitle: Membership.membershipTitle,
                     membershipShort: Membership.membershipShort,
                     labelAddedDate : QUILocale.get(lg, lgPrefix + 'labelAddedDate'),
                     addedDate      : Membership.addedDate,
                     labelEndDate   : endDateLabel,
                     endDate        : endDateValue,
-                    labelStatus    : QUILocale.get(lg, lgPrefix + 'labelStatus'),
+                    labelStatus    : QUILocale.get(lg, lgPrefix + 'labelStatus')
                 })
             });
 
@@ -217,11 +204,11 @@ define('package/quiqqer/memberships/bin/controls/profile/UserProfile', [
             // show content btn
             if (Membership.membershipContent !== '') {
                 var ShowContentElm = MembershipElm.getElement(
-                    '.quiqqer-memberships-profile-userprofile-membership-info-title'
+                    '.quiqqer-memberships-profile-userprofile-membership-header-info'
                 );
 
                 new Element('span', {
-                    'class': 'fa fa-info-circle quiqqer-memberships-profile-userprofile-membership-info-content',
+                    'class': 'fa fa-info-circle quiqqer-memberships-profile-userprofile-membership-header-info-icon',
                     events : {
                         click: function () {
                             self.$showMembershipContent(Membership);
diff --git a/composer.json b/composer.json
index 22f45d115b0719331741fcf5f20b1401d31a7458..977fee855665e2296e338eaa1ee8c351c3222670 100644
--- a/composer.json
+++ b/composer.json
@@ -3,7 +3,10 @@
   "type": "quiqqer-module",
   "description": "The Membership Module is an easy to use Membership Plugin. It will give you the ability to confidently create, manage and track membership subscriptions. In addition to these powerful abilities, the Membership Module will allow you to grant and revoke permissions to Users.",
   "version": "dev-dev",
-  "license": ["PCSG QL-1.0", "CC BY-NC-SA 4.0"],
+  "license": [
+    "PCSG QL-1.0",
+    "CC BY-NC-SA 4.0"
+  ],
   "authors": [
     {
       "name": "Patrick Müller",
@@ -17,7 +20,7 @@
     "url": "http://www.pcsg.de"
   },
   "require": {
-    "quiqqer/verification": "dev-dev"
+    "quiqqer/verification": "1.*|*@dev"
   },
   "autoload": {
     "psr-4": {
diff --git a/events.xml b/events.xml
index 61f4baef1fa685a37aa7a68c789b3f6fa4acd461..a78477fbc06fc3121135fefb62ff51c7ef125970 100644
--- a/events.xml
+++ b/events.xml
@@ -3,4 +3,5 @@
     <event on="onPackageSetup" fire="\QUI\Memberships\Events::onPackageSetup"/>
     <event on="onUserSave" fire="\QUI\Memberships\Events::onUserSave"/>
     <event on="onOrderSuccess" fire="\QUI\Memberships\Events::onOrderSuccess"/>
+    <event on="onQuiqqerProductsFieldDelete" fire="\QUI\Memberships\Events::onQuiqqerProductsFieldDelete"/>
 </events>
\ No newline at end of file
diff --git a/frontend-users.xml b/frontend-users.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c23dc952db2c0acaed9d3c3d0deab692aa98d9d7
--- /dev/null
+++ b/frontend-users.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<quiqqer>
+    <frontend-users>
+        <profile>
+            <categories>
+                <category name="memberships">
+                    <title>
+                        <locale group="quiqqer/memberships" var="profile.category.memberships.title"/>
+                    </title>
+
+                    <!-- User Data -->
+                    <settings control="\QUI\Memberships\Controls\Profile\Memberships"
+                              name="mymemberships"
+                              icon="fa fa-id-card-o"
+                              showinprofilebar="1"
+                    >
+                        <title>
+                            <locale group="quiqqer/memberships" var="profile.mymemberships.title"/>
+                        </title>
+                    </settings>
+
+                </category>
+            </categories>
+
+        </profile>
+    </frontend-users>
+</quiqqer>
diff --git a/intranet.xml b/intranet.xml
deleted file mode 100644
index 2e601af0ef779f5b646adafca2aa9786cd684506..0000000000000000000000000000000000000000
--- a/intranet.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<menu>
-    <item require="package/quiqqer/memberships/bin/controls/profile/UserProfile" icon="fa fa-id-card-o" name="memberships-profile">
-        <locale group="quiqqer/memberships" var="profile.button.text" />
-    </item>
-</menu>
diff --git a/locale.xml b/locale.xml
index a0ffe4f0d7cfe7e771cd555ef7f0265f5d88e9a6..011489a7c822f48591cd494d33ed0205eed3d52d 100644
--- a/locale.xml
+++ b/locale.xml
@@ -169,6 +169,14 @@
             <de><![CDATA[Mitgliedschaft, in die alle Benutzer im System automatisch gesetzt werden. Benutzer haben keine Möglichkeit diese Mitgliedschaft zu kündigen.]]></de>
             <en><![CDATA[Membership in which all users in the system are automatically put. Users have no option to cancel this membership.]]></en>
         </locale>
+        <locale name="settings.membershipFieldId.title">
+            <de><![CDATA[Mitgliedschaft Produktfeld]]></de>
+            <en><![CDATA[Membership product field]]></en>
+        </locale>
+        <locale name="settings.membershipFieldId.description">
+            <de><![CDATA[Legt das Produktfeld fest, über welches Produkten jeweils eine Mitgliedschaft zugeordnet wird.]]></de>
+            <en><![CDATA[Determines the product field that is used to assign a memebership to a product.]]></en>
+        </locale>
 
         <!-- Cron -->
         <locale name="cron.checkMembershipUsers.title">
@@ -181,10 +189,14 @@
         </locale>
 
         <!-- Profile -->
-        <locale name="profile.button.text">
+        <locale name="profile.category.memberships.title">
             <de><![CDATA[Mitgliedschaften]]></de>
             <en><![CDATA[Memberships]]></en>
         </locale>
+        <locale name="profile.mymemberships.title">
+            <de><![CDATA[Meine Mitgliedschaften]]></de>
+            <en><![CDATA[My memberships]]></en>
+        </locale>
 
         <!-- quiqqer/products -->
         <locale name="products.field.membership">
@@ -208,6 +220,112 @@
 
     <groups name="quiqqer/memberships" datatype="js">
 
+        <!-- Control: profile/UserProfile -->
+        <locale name="controls.profile.userprofile.template.header">
+            <de><![CDATA[Meine Mitgliedschaften]]></de>
+            <en><![CDATA[My memberships]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.template.headerMembership">
+            <de><![CDATA[Mitgliedschaft]]></de>
+            <en><![CDATA[Membership]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.template.headerMembershipData">
+            <de><![CDATA[Details]]></de>
+            <en><![CDATA[Details]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.datatable.labelAddedDate">
+            <de><![CDATA[In Mitgliedschaft seit]]></de>
+            <en><![CDATA[In membership since]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.datatable.labelEndDate.autoExtend">
+            <de><![CDATA[Autom. Verlängerung am]]></de>
+            <en><![CDATA[Auto extend at]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.datatable.labelEndDate.noAutoExtend">
+            <de><![CDATA[Mitgliedschaft endet]]></de>
+            <en><![CDATA[Membership ends]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.datatable.endDate.infinite">
+            <de><![CDATA[-]]></de>
+            <en><![CDATA[-]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.datatable.labelStatus">
+            <de><![CDATA[Status]]></de>
+            <en><![CDATA[Status]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.datatable.status.cancelled">
+            <de><![CDATA[gekündigt]]></de>
+            <en><![CDATA[cancelled]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.datatable.status.active">
+            <de><![CDATA[aktiv]]></de>
+            <en><![CDATA[active]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.btn.cancel.text">
+            <de><![CDATA[Mitgliedschaft kündigen]]></de>
+            <en><![CDATA[Cancel membership]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.btn.abortcancel.text">
+            <de><![CDATA[Kündigung zurückziehen]]></de>
+            <en><![CDATA[Withdraw cancellation]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.cancelconfirm.info" html="true">
+            <de><![CDATA[Sind Sie sicher, dass Sie die Mitgliedschaft <b>[title]</b> kündigen wollen? Bitte beachten Sie, dass Ihre Mitgliedschaft dann zum <b>[endDate]</b> ausläuft. Bis dahin können Sie weiterhin alle Vorteile Ihrer Mitgliedschaft nutzen. Bis zum Ablaufdatum können Sie die Kündigung jederzeit zurückziehen.]]></de>
+            <en><![CDATA[Are you sure you want to cancel your <b>[title]</b> membership? Please note that your membership expires by <b>[endDate]</b>. Until then, you can continue to take full advantage of your membership. Until the expiration date, you can withdraw the cancellation at any time.]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.cancelconfirm.text">
+            <de><![CDATA[Kündigung der Mitgliedschaft "[title]"]]></de>
+            <en><![CDATA[Cancellation of membership "[title]"]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.cancelconfirm.title">
+            <de><![CDATA[Mitgliedschaft kündigen]]></de>
+            <en><![CDATA[Cancel membership]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.cancelconfirm.cancel">
+            <de><![CDATA[Abbrechen]]></de>
+            <en><![CDATA[Abbrechen]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.cancelconfirm.ok">
+            <de><![CDATA[Mitgliedschaft kündigen]]></de>
+            <en><![CDATA[Cancel membership]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.abortcancel.info" html="true">
+            <de><![CDATA[Sind Sie sicher, dass Sie die Kündigung Ihrer Mitgliedschaft <b>[title]</b> zurückziehen wollen?]]></de>
+            <en><![CDATA[Are you sure you want to withdraw the cancellation of your <b>[title]</b> membership?]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.abortcancel.text">
+            <de><![CDATA[Kündigung der Mitgliedschaft "[title]" zurückziehen]]></de>
+            <en><![CDATA[Withdraw cancellation of membership "[title]"]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.abortcancel.title">
+            <de><![CDATA[Mitgliedschafts-Kündigung zurückziehen]]></de>
+            <en><![CDATA[Withdraw cancellation membership]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.abortcancel.cancel">
+            <de><![CDATA[Abbrechen]]></de>
+            <en><![CDATA[Abbrechen]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.abortcancel.ok">
+            <de><![CDATA[Kündigung zurückziehen]]></de>
+            <en><![CDATA[Withdraw cancellation]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.info.no.memberships">
+            <de><![CDATA[Es sind z.Z. keine Mitgliedschaften in Ihrem Nutzerprofil vorhanden.]]></de>
+            <en><![CDATA[There are currently no memberships in your user profile.]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.showcontent.title">
+            <de><![CDATA[Mitgliedschaft "[title]"]]></de>
+            <en><![CDATA[Membership "[title]"]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.status.modifier.cancel_confirm">
+            <de><![CDATA[(Kündigung beantragt - Bestätigung ausstehend)]]></de>
+            <en><![CDATA[(Cancellation requested - confirmation pending)]]></en>
+        </locale>
+        <locale name="controls.profile.userprofile.status.modifier.abortcancel_confirm">
+            <de><![CDATA[(Kündigung zurückgezogen - Bestätigung ausstehend)]]></de>
+            <en><![CDATA[(Cancellation withdrawn - confirmation pending)]]></en>
+        </locale>
+
         <!-- Control: MembershipsSearchPopup -->
         <locale name="controls.membershipssearchpopup.title">
             <de><![CDATA[Mitgliedschafts-Verwaltung]]></de>
@@ -800,112 +918,6 @@
             <en><![CDATA[Send confirmation]]></en>
         </locale>
 
-        <!-- Control: profile/UserProfile -->
-        <locale name="controls.profile.userprofile.template.header">
-            <de><![CDATA[Ihre Mitgliedschaften]]></de>
-            <en><![CDATA[Your memberships]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.template.headerMembership">
-            <de><![CDATA[Mitgliedschaft]]></de>
-            <en><![CDATA[Membership]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.template.headerMembershipData">
-            <de><![CDATA[Details]]></de>
-            <en><![CDATA[Details]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.datatable.labelAddedDate">
-            <de><![CDATA[In Mitgliedschaft seit]]></de>
-            <en><![CDATA[In membership since]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.datatable.labelEndDate.autoExtend">
-            <de><![CDATA[Autom. Verlängerung am]]></de>
-            <en><![CDATA[Auto extend at]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.datatable.labelEndDate.noAutoExtend">
-            <de><![CDATA[Mitgliedschaft endet]]></de>
-            <en><![CDATA[Membership ends]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.datatable.endDate.infinite">
-            <de><![CDATA[-]]></de>
-            <en><![CDATA[-]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.datatable.labelStatus">
-            <de><![CDATA[Status]]></de>
-            <en><![CDATA[Status]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.datatable.status.cancelled">
-            <de><![CDATA[gekündigt]]></de>
-            <en><![CDATA[cancelled]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.datatable.status.active">
-            <de><![CDATA[aktiv]]></de>
-            <en><![CDATA[active]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.btn.cancel.text">
-            <de><![CDATA[Mitgliedschaft kündigen]]></de>
-            <en><![CDATA[Cancel membership]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.btn.abortcancel.text">
-            <de><![CDATA[Kündigung zurückziehen]]></de>
-            <en><![CDATA[Withdraw cancellation]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.cancelconfirm.info" html="true">
-            <de><![CDATA[Sind Sie sicher, dass Sie die Mitgliedschaft <b>[title]</b> kündigen wollen? Bitte beachten Sie, dass Ihre Mitgliedschaft dann zum <b>[endDate]</b> ausläuft. Bis dahin können Sie weiterhin alle Vorteile Ihrer Mitgliedschaft nutzen. Bis zum Ablaufdatum können Sie die Kündigung jederzeit zurückziehen.]]></de>
-            <en><![CDATA[Are you sure you want to cancel your <b>[title]</b> membership? Please note that your membership expires by <b>[endDate]</b>. Until then, you can continue to take full advantage of your membership. Until the expiration date, you can withdraw the cancellation at any time.]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.cancelconfirm.text">
-            <de><![CDATA[Kündigung der Mitgliedschaft "[title]"]]></de>
-            <en><![CDATA[Cancellation of membership "[title]"]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.cancelconfirm.title">
-            <de><![CDATA[Mitgliedschaft kündigen]]></de>
-            <en><![CDATA[Cancel membership]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.cancelconfirm.cancel">
-            <de><![CDATA[Abbrechen]]></de>
-            <en><![CDATA[Abbrechen]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.cancelconfirm.ok">
-            <de><![CDATA[Mitgliedschaft kündigen]]></de>
-            <en><![CDATA[Cancel membership]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.abortcancel.info" html="true">
-            <de><![CDATA[Sind Sie sicher, dass Sie die Kündigung Ihrer Mitgliedschaft <b>[title]</b> zurückziehen wollen?]]></de>
-            <en><![CDATA[Are you sure you want to withdraw the cancellation of your <b>[title]</b> membership?]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.abortcancel.text">
-            <de><![CDATA[Kündigung der Mitgliedschaft "[title]" zurückziehen]]></de>
-            <en><![CDATA[Withdraw cancellation of membership "[title]"]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.abortcancel.title">
-            <de><![CDATA[Mitgliedschafts-Kündigung zurückziehen]]></de>
-            <en><![CDATA[Withdraw cancellation membership]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.abortcancel.cancel">
-            <de><![CDATA[Abbrechen]]></de>
-            <en><![CDATA[Abbrechen]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.abortcancel.ok">
-            <de><![CDATA[Kündigung zurückziehen]]></de>
-            <en><![CDATA[Withdraw cancellation]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.info.no.memberships">
-            <de><![CDATA[Es sind z.Z. keine Mitgliedschaften in Ihrem Nutzerprofil vorhanden.]]></de>
-            <en><![CDATA[There are currently no memberships in your user profile.]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.showcontent.title">
-            <de><![CDATA[Mitgliedschaft "[title]"]]></de>
-            <en><![CDATA[Membership "[title]"]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.status.modifier.cancel_confirm">
-            <de><![CDATA[(Kündigung beantragt - Bestätigung ausstehend)]]></de>
-            <en><![CDATA[(Cancellation requested - confirmation pending)]]></en>
-        </locale>
-        <locale name="controls.profile.userprofile.status.modifier.abortcancel_confirm">
-            <de><![CDATA[(Kündigung zurückgezogen - Bestätigung ausstehend)]]></de>
-            <en><![CDATA[(Cancellation withdrawn - confirmation pending)]]></en>
-        </locale>
-
         <!-- Templates -->
         <locale name="templates.mail.greeting">
             <de><![CDATA[Hallo [name]!]]></de>
@@ -978,12 +990,12 @@
             <en><![CDATA[The membership has already been cancelled.]]></en>
         </locale>
         <locale name="verification.abortcancel.success.autoExtend">
-            <de><![CDATA[Die Kündigung Ihrer Mitgliedschaft wurde erfolgreich zurückgezogen! Die Mitgliedschaft erneuert sich weiterhin automatisch am [endDate].]]></de>
-            <en><![CDATA[The termination of your membership has been withdrawn successfully! You membership will automatically extend at [endDate].]]></en>
+            <de><![CDATA[Die Kündigung Ihrer Mitgliedschaft "[membershipTitle]" wurde erfolgreich zurückgezogen! Die Mitgliedschaft erneuert sich weiterhin automatisch am [endDate].]]></de>
+            <en><![CDATA[The termination of your membership "[membershipTitle]" has been withdrawn successfully! You membership will automatically extend at [endDate].]]></en>
         </locale>
         <locale name="verification.abortcancel.success.noAutoExtend">
-            <de><![CDATA[Die Kündigung Ihrer Mitgliedschaft wurde erfolgreich zurückgezogen. Sie läuft automatisch zum [endDate] aus.]]></de>
-            <en><![CDATA[The termination of your membership has been withdrawn successfully. It automatically expires at [endDate].]]></en>
+            <de><![CDATA[Die Kündigung Ihrer Mitgliedschaft "[membershipTitle]" wurde erfolgreich zurückgezogen. Sie läuft automatisch zum [endDate] aus.]]></de>
+            <en><![CDATA[The termination of your membership "[membershipTitle]" has been withdrawn successfully. It automatically expires at [endDate].]]></en>
         </locale>
         <locale name="verification.abortcancel.error.general">
             <de><![CDATA[Beim Zurückziehen Ihrer Kündigung ist ein Fehler aufgetreten. Bitte starten Sie den Vorgang erneut oder kontaktieren Sie einen Administrator.]]></de>
diff --git a/settings.xml b/settings.xml
index 56d21c71df836f5ad99b179cd256153fb8ac0917..8f0aa07f7025bd8806c0370e22e26adb9bbd573a 100644
--- a/settings.xml
+++ b/settings.xml
@@ -54,6 +54,12 @@
                 <conf name="categoryId">
                     <type><![CDATA[integer]]></type>
                 </conf>
+                <conf name="membershipFieldId">
+                    <type><![CDATA[integer]]></type>
+                </conf>
+                <conf name="membershipFlagFieldId">
+                    <type><![CDATA[integer]]></type>
+                </conf>
             </section>
 
         </config>
diff --git a/src/QUI/Memberships/Controls/Profile/Memberships.html b/src/QUI/Memberships/Controls/Profile/Memberships.html
new file mode 100644
index 0000000000000000000000000000000000000000..6d1d8ddea89982c7fe43f31bb08348e0ad223bbe
--- /dev/null
+++ b/src/QUI/Memberships/Controls/Profile/Memberships.html
@@ -0,0 +1 @@
+<div class="quiqqer-memberships-profile-memberships"></div>
\ No newline at end of file
diff --git a/src/QUI/Memberships/Controls/Profile/Memberships.php b/src/QUI/Memberships/Controls/Profile/Memberships.php
new file mode 100644
index 0000000000000000000000000000000000000000..8e34e47b5281af40a265b5c14de33059f3c18e5e
--- /dev/null
+++ b/src/QUI/Memberships/Controls/Profile/Memberships.php
@@ -0,0 +1,55 @@
+<?php
+
+namespace QUI\Memberships\Controls\Profile;
+
+use QUI;
+use QUI\FrontendUsers\Controls\Profile\AbstractProfileControl;
+
+class Memberships extends AbstractProfileControl
+{
+    /**
+     * Constructor
+     *
+     * @param array $attributes
+     */
+    public function __construct(array $attributes = [])
+    {
+        parent::__construct($attributes);
+        $this->setJavaScriptControl('package/quiqqer/memberships/bin/controls/profile/UserProfile');
+    }
+
+    /**
+     * Return the inner body of the element
+     * Can be overwritten
+     *
+     * @return string
+     * @throws \QUI\Exception
+     */
+    public function getBody()
+    {
+        $Engine = QUI::getTemplateManager()->getEngine();
+        return $Engine->fetch(dirname(__FILE__).'/Memberships.html');
+    }
+
+    /**
+     * Method is called, when on save is triggered
+     *
+     * @return mixed|void
+     */
+    public function onSave()
+    {
+        \QUI\System\Log::writeRecursive("onSave");
+    }
+
+    /**
+     * Validate the send data
+     *
+     * @return mixed|void
+     * @throws \Exception
+     */
+    public function validate()
+    {
+        \QUI\System\Log::writeRecursive("validate");
+    }
+
+}
diff --git a/src/QUI/Memberships/Events.php b/src/QUI/Memberships/Events.php
index 1042d517946c7ef034ff46ede7c3c1de174ab22e..74515c34a135dec146c632bc3a34384aeac36383 100644
--- a/src/QUI/Memberships/Events.php
+++ b/src/QUI/Memberships/Events.php
@@ -8,6 +8,7 @@
 use QUI\Memberships\Users\Handler as MembershipUsersHandler;
 use QUI\Memberships\Products\MembershipField;
 use QUI\ERP\Products\Handler\Fields as ProductFields;
+use QUI\ERP\Products\Field\Field as ProductField;
 use QUI\ERP\Products\Handler\Categories as ProductCategories;
 use QUI\ERP\Products\Handler\Search as ProductSearchHandler;
 use QUI\ERP\Products\Product\Product;
@@ -34,17 +35,21 @@ public static function onPackageSetup(Package $Package)
 
         $packages = Utils::getInstalledMembershipPackages();
 
-        foreach ($packages as $package) {
-            switch ($package) {
-                case 'quiqqer/products':
-                    self::createProductFields();
-                    self::createProductCategory();
-                    break;
-
-                case 'quiqqer/contracts':
-                    // @todo setup routine for quiqqer/contracts
-                    break;
+        try {
+            foreach ($packages as $package) {
+                switch ($package) {
+                    case 'quiqqer/products':
+                        self::createProductFields();
+                        self::createProductCategory();
+                        break;
+
+                    case 'quiqqer/contracts':
+                        // @todo setup routine for quiqqer/contracts
+                        break;
+                }
             }
+        } catch (\Exception $Exception) {
+            QUI\System\Log::writeException($Exception);
         }
     }
 
@@ -56,8 +61,14 @@ public static function onPackageSetup(Package $Package)
      */
     public static function onQuiqqerProductsProductDelete(Product $Product)
     {
+        $membershipFieldId = Handler::getProductMembershipField()->getId();
+
+        if (!$membershipFieldId) {
+            return;
+        }
+
         // check if Product is assigned to a Membership
-        $membershipId = $Product->getFieldValue(MembershipsHandler::PRODUCTS_FIELD_MEMBERSHIP);
+        $membershipId = $Product->getFieldValue($membershipFieldId);
 
         if (empty($membershipId)) {
             return;
@@ -68,9 +79,9 @@ public static function onQuiqqerProductsProductDelete(Product $Product)
             $Membership      = MembershipsHandler::getInstance()->getChild($membershipId);
             $MembershipUsers = MembershipUsersHandler::getInstance();
 
-            $membershipUserIds = $Membership->searchUsers(array(
+            $membershipUserIds = $Membership->searchUsers([
                 'productId' => $Product->getId()
-            ));
+            ]);
 
             foreach ($membershipUserIds as $membershipUserId) {
                 $MembershipUser = $MembershipUsers->getChild($membershipUserId);
@@ -79,8 +90,8 @@ public static function onQuiqqerProductsProductDelete(Product $Product)
             }
         } catch (\Exception $Exception) {
             QUI\System\Log::addError(
-                self::class . ' :: onQuiqqerProductsProductDelete -> '
-                . $Exception->getMessage()
+                self::class.' :: onQuiqqerProductsProductDelete -> '
+                .$Exception->getMessage()
             );
         }
     }
@@ -113,82 +124,93 @@ public static function onUserSave(QUI\Users\User $User)
     /**
      * quiqqer/products
      *
-     * Create a Membership field with a fixed id and a membership flag field that
-     * identifies a product as a Membership product
+     * Create necessary membership product fields and save their IDs to the config
      *
      * @return void
+     * @throws \QUI\Exception
      */
     protected static function createProductFields()
     {
-        $L = new QUI\Locale();
-
-        // Membership field
-        $translations = array(
-            'de' => '',
-            'en' => ''
-        );
+        $L    = new QUI\Locale();
+        $Conf = QUI::getPackage('quiqqer/memberships')->getConfig();
 
-        foreach ($translations as $l => $t) {
-            $L->setCurrent($l);
-            $translations[$l] = $L->get(
-                'quiqqer/memberships',
-                'products.field.membership'
-            );
-        }
+        // Membership field (create new one is not configured)
+        $MembershipField = Handler::getProductMembershipField();
+
+        if ($MembershipField === false) {
+            $translations = [
+                'de' => '',
+                'en' => ''
+            ];
+
+            foreach ($translations as $l => $t) {
+                $L->setCurrent($l);
+                $translations[$l] = $L->get(
+                    'quiqqer/memberships',
+                    'products.field.membership'
+                );
+            }
 
-        try {
-            $NewField = ProductFields::createField(array(
-                'id'            => MembershipsHandler::PRODUCTS_FIELD_MEMBERSHIP,
-                'type'          => MembershipField::TYPE,
-                'titles'        => $translations,
-                'workingtitles' => $translations
-            ));
-
-            $NewField->setAttribute('search_type', ProductSearchHandler::SEARCHTYPE_TEXT);
-            $NewField->save();
-        } catch (\QUI\ERP\Products\Field\Exception $Exception) {
-            // nothing, field exists
-        } catch (\Exception $Exception) {
-            QUI\System\Log::addError(self::class . ' :: createProductFields');
-            QUI\System\Log::writeException($Exception);
+            try {
+                $MembershipField = ProductFields::createField([
+                    'type'          => MembershipField::TYPE,
+                    'titles'        => $translations,
+                    'workingtitles' => $translations
+                ]);
+
+                $MembershipField->setAttribute('search_type', ProductSearchHandler::SEARCHTYPE_TEXT);
+                $MembershipField->save();
+
+                // add field id to config
+                $Conf->set('products', 'membershipFieldId', $MembershipField->getId());
+                $Conf->save();
+            } catch (\Exception $Exception) {
+                QUI\System\Log::addError(self::class.' :: createProductFields');
+                QUI\System\Log::writeException($Exception);
+            }
         }
 
-        // membership flag field
-        $translations = array(
-            'de' => '',
-            'en' => ''
-        );
-
-        foreach ($translations as $l => $t) {
-            $L->setCurrent($l);
-            $translations[$l] = $L->get(
-                'quiqqer/memberships',
-                'products.field.membershipflag'
-            );
-        }
+        // Membership flag field (create new one is not configured)
+        $MembershipFlagField = Handler::getProductMembershipFlagField();
+
+        if ($MembershipFlagField === false) {
+            $translations = [
+                'de' => '',
+                'en' => ''
+            ];
+
+            foreach ($translations as $l => $t) {
+                $L->setCurrent($l);
+                $translations[$l] = $L->get(
+                    'quiqqer/memberships',
+                    'products.field.membershipflag'
+                );
+            }
 
-        try {
-            $NewField = ProductFields::createField(array(
-                'id'            => MembershipsHandler::PRODUCTS_FIELD_MEMBERSHIPFLAG,
-                'type'          => ProductFields::TYPE_BOOL,
-                'titles'        => $translations,
-                'workingtitles' => $translations
-            ));
-
-            $NewField->setAttribute('search_type', ProductSearchHandler::SEARCHTYPE_BOOL);
-            $NewField->save();
-
-            // add Flag field to backend search
-            $BackendSearch                    = ProductSearchHandler::getBackendSearch();
-            $searchFields                     = $BackendSearch->getSearchFields();
-            $searchFields[$NewField->getId()] = true;
-
-            $BackendSearch->setSearchFields($searchFields);
-        } catch (\QUI\ERP\Products\Field\Exception $Exception) {
-            // nothing, field exists
-        } catch (\Exception $Exception) {
-            QUI\System\Log::addError(self::class . ' :: createProductFields');
-            QUI\System\Log::writeException($Exception);
+            try {
+                $MembershipFlagField = ProductFields::createField([
+                    'type'          => ProductFields::TYPE_BOOL,
+                    'titles'        => $translations,
+                    'workingtitles' => $translations
+                ]);
+
+                $MembershipFlagField->setAttribute('search_type', ProductSearchHandler::SEARCHTYPE_BOOL);
+                $MembershipFlagField->save();
+
+                // add Flag field to backend search
+                $BackendSearch                               = ProductSearchHandler::getBackendSearch();
+                $searchFields                                = $BackendSearch->getSearchFields();
+                $searchFields[$MembershipFlagField->getId()] = true;
+
+                $BackendSearch->setSearchFields($searchFields);
+
+                // add field id to config
+                $Conf->set('products', 'membershipFlagFieldId', $MembershipFlagField->getId());
+                $Conf->save();
+            } catch (\Exception $Exception) {
+                QUI\System\Log::addError(self::class.' :: createProductFields');
+                QUI\System\Log::writeException($Exception);
+            }
         }
     }
 
@@ -207,6 +229,12 @@ public static function onOrderSuccess(AbstractOrder $Order)
         }
     }
 
+    public static function onQuiqqerProductsFieldDelete(ProductField $Field)
+    {
+        $Conf = QUI::getPackage('quiqqer/memberships')->getConfig();
+        $membershipFieldId =
+    }
+
     /**
      * Create a product category for memberships
      *
@@ -224,22 +252,22 @@ protected static function createProductCategory()
         try {
             $Category = ProductCategories::createCategory();
         } catch (\Exception $Exception) {
-            QUI\System\Log::addError(self::class . ' :: createProductCategory()');
+            QUI\System\Log::addError(self::class.' :: createProductCategory()');
             QUI\System\Log::writeException($Exception);
 
             return;
         }
 
         $catId  = $Category->getId();
-        $titles = array(
+        $titles = [
             'de' => '',
             'en' => ''
-        );
+        ];
 
-        $descriptions = array(
+        $descriptions = [
             'de' => '',
             'en' => ''
-        );
+        ];
 
         $L = new QUI\Locale();
 
@@ -248,36 +276,36 @@ protected static function createProductCategory()
             $t = $L->get('quiqqer/memberships', 'products.category.title');
             $d = $L->get('quiqqer/memberships', 'products.category.description');
 
-            $titles[$l]                 = $t;
-            $titles[$l . '_edit']       = $t;
-            $descriptions[$l]           = $d;
-            $descriptions[$l . '_edit'] = $d;
+            $titles[$l]               = $t;
+            $titles[$l.'_edit']       = $t;
+            $descriptions[$l]         = $d;
+            $descriptions[$l.'_edit'] = $d;
         }
 
         // change title and description
         QUI\Translator::edit(
             'quiqqer/products',
-            'products.category.' . $catId . '.title',
+            'products.category.'.$catId.'.title',
             'quiqqer/products',
             array_merge(
                 $titles,
-                array(
+                [
                     'datatype' => 'php,js',
                     'html'     => 0
-                )
+                ]
             )
         );
 
         QUI\Translator::edit(
             'quiqqer/products',
-            'products.category.' . $catId . '.description',
+            'products.category.'.$catId.'.description',
             'quiqqer/products',
             array_merge(
                 $descriptions,
-                array(
+                [
                     'datatype' => 'php,js',
                     'html'     => 0
-                )
+                ]
             )
         );
 
diff --git a/src/QUI/Memberships/Handler.php b/src/QUI/Memberships/Handler.php
index bd885761b3dd49fd077e29f884aaf9a6a7a96f97..620c6c3106d293be8d77629c59e15deac2173620 100644
--- a/src/QUI/Memberships/Handler.php
+++ b/src/QUI/Memberships/Handler.php
@@ -21,17 +21,11 @@ class Handler extends Factory
     const PERMISSION_DELETE     = 'quiqqer.memberships.delete';
     const PERMISSION_FORCE_EDIT = 'quiqqer.memberships.force_edit';
 
-    /**
-     * quiqqer/products field IDs
-     */
-    const PRODUCTS_FIELD_MEMBERSHIP     = 102;
-    const PRODUCTS_FIELD_MEMBERSHIPFLAG = 103;
-
     /**
      * @inheritdoc
      * @throws QUI\Memberships\Exception
      */
-    public function createChild($data = array())
+    public function createChild($data = [])
     {
         Permission::checkPermission(self::PERMISSION_CREATE);
 
@@ -42,13 +36,13 @@ public function createChild($data = array())
         $title = trim($data['title']);
 
         if (empty($title)) {
-            throw new QUI\Memberships\Exception(array(
+            throw new QUI\Memberships\Exception([
                 'quiqqer/memberships',
                 'exception.handler.no.title'
-            ));
+            ]);
         }
 
-        $data['title'] = array();
+        $data['title'] = [];
 
         foreach (QUI::availableLanguages() as $lang) {
             $data['title'][$lang] = $title;
@@ -63,10 +57,10 @@ public function createChild($data = array())
         if (empty($groupIds)
             || !is_array($groupIds)
         ) {
-            throw new QUI\Memberships\Exception(array(
+            throw new QUI\Memberships\Exception([
                 'quiqqer/memberships',
                 'exception.handler.no.groups'
-            ));
+            ]);
         }
 
         foreach ($groupIds as $groupId) {
@@ -74,7 +68,7 @@ public function createChild($data = array())
             $Groups->get((int)$groupId);
         }
 
-        $data['groupIds'] = ',' . implode(',', $groupIds) . ',';
+        $data['groupIds'] = ','.implode(',', $groupIds).',';
         $data['duration'] = '1-month';
 
         /** @var Membership $NewMembership */
@@ -119,7 +113,7 @@ public function getChildClass()
      */
     public function getChildAttributes()
     {
-        return array(
+        return [
             'title',
             'description',
             'content',
@@ -133,7 +127,7 @@ public function getChildAttributes()
             'paymentInterval'
 
             // @todo additional fields for quiqqer/contracts
-        );
+        ];
     }
 
     /**
@@ -145,12 +139,12 @@ public function getChildAttributes()
      */
     public function search($searchParams, $countOnly = false)
     {
-        $memberships = array();
+        $memberships = [];
         $Grid        = new Grid($searchParams);
         $gridParams  = $Grid->parseDBParams($searchParams);
 
-        $binds = array();
-        $where = array();
+        $binds = [];
+        $where = [];
 
         if ($countOnly) {
             $sql = "SELECT COUNT(*)";
@@ -158,14 +152,14 @@ public function search($searchParams, $countOnly = false)
             $sql = "SELECT id";
         }
 
-        $sql .= " FROM `" . $this->getDataBaseTableName() . "`";
+        $sql .= " FROM `".$this->getDataBaseTableName()."`";
 
         if (!empty($searchParams['userId'])) {
             $memberhsipUsers = MembershipUsersHandler::getInstance()->getMembershipUsersByUserId(
                 (int)$searchParams['userId']
             );
 
-            $membershipIds = array();
+            $membershipIds = [];
 
             /** @var QUI\Memberships\Users\MembershipUser $MembershipUser */
             foreach ($memberhsipUsers as $MembershipUser) {
@@ -173,63 +167,63 @@ public function search($searchParams, $countOnly = false)
             }
 
             if (!empty($membershipIds)) {
-                $where[] = '`id` IN (' . implode(',', $membershipIds) . ')';
+                $where[] = '`id` IN ('.implode(',', $membershipIds).')';
             }
         }
 
         if (!empty($searchParams['search'])) {
-            $searchColumns = array(
+            $searchColumns = [
                 'title',
                 'description',
                 'content'
-            );
+            ];
 
-            $whereOr = array();
+            $whereOr = [];
 
             foreach ($searchColumns as $searchColumn) {
-                $whereOr[] = '`' . $searchColumn . '` LIKE :search';
+                $whereOr[] = '`'.$searchColumn.'` LIKE :search';
             }
 
             if (!empty($whereOr)) {
-                $where[] = '(' . implode(' OR ', $whereOr) . ')';
+                $where[] = '('.implode(' OR ', $whereOr).')';
 
-                $binds['search'] = array(
-                    'value' => '%' . $searchParams['search'] . '%',
+                $binds['search'] = [
+                    'value' => '%'.$searchParams['search'].'%',
                     'type'  => \PDO::PARAM_STR
-                );
+                ];
             }
         }
 
         // build WHERE query string
         if (!empty($where)) {
-            $sql .= " WHERE " . implode(" AND ", $where);
+            $sql .= " WHERE ".implode(" AND ", $where);
         }
 
         // ORDER
         if (!empty($searchParams['sortOn'])
         ) {
             $sortOn = Orthos::clear($searchParams['sortOn']);
-            $order  = "ORDER BY " . $sortOn;
+            $order  = "ORDER BY ".$sortOn;
 
             if (isset($searchParams['sortBy']) &&
                 !empty($searchParams['sortBy'])
             ) {
-                $order .= " " . Orthos::clear($searchParams['sortBy']);
+                $order .= " ".Orthos::clear($searchParams['sortBy']);
             } else {
                 $order .= " ASC";
             }
 
-            $sql .= " " . $order;
+            $sql .= " ".$order;
         }
 
         // LIMIT
         if (!empty($gridParams['limit'])
             && !$countOnly
         ) {
-            $sql .= " LIMIT " . $gridParams['limit'];
+            $sql .= " LIMIT ".$gridParams['limit'];
         } else {
             if (!$countOnly) {
-                $sql .= " LIMIT " . (int)20;
+                $sql .= " LIMIT ".(int)20;
             }
         }
 
@@ -237,7 +231,7 @@ public function search($searchParams, $countOnly = false)
 
         // bind search values
         foreach ($binds as $var => $bind) {
-            $Stmt->bindValue(':' . $var, $bind['value'], $bind['type']);
+            $Stmt->bindValue(':'.$var, $bind['value'], $bind['type']);
         }
 
         try {
@@ -245,10 +239,10 @@ public function search($searchParams, $countOnly = false)
             $result = $Stmt->fetchAll(\PDO::FETCH_ASSOC);
         } catch (\Exception $Exception) {
             QUI\System\Log::addError(
-                self::class . ' :: searchUsers() -> ' . $Exception->getMessage()
+                self::class.' :: searchUsers() -> '.$Exception->getMessage()
             );
 
-            return array();
+            return [];
         }
 
         if ($countOnly) {
@@ -270,24 +264,24 @@ public function search($searchParams, $countOnly = false)
      */
     public function getMembershipIdsByGroupIds($groupIds)
     {
-        $ids = array();
+        $ids = [];
 
         if (empty($groupIds)) {
             return $ids;
         }
 
-        $sql = 'SELECT `id` FROM ' . self::getDataBaseTableName();
+        $sql = 'SELECT `id` FROM '.self::getDataBaseTableName();
         $sql .= ' WHERE ';
 
-        $whereOr = array();
-        $binds   = array();
+        $whereOr = [];
+        $binds   = [];
 
         foreach ($groupIds as $groupId) {
-            $whereOr[]       = '`groupIds` LIKE :' . $groupId;
-            $binds[$groupId] = array(
-                'value' => '%,' . $groupId . ',%',
+            $whereOr[]       = '`groupIds` LIKE :'.$groupId;
+            $binds[$groupId] = [
+                'value' => '%,'.$groupId.',%',
                 'type'  => \PDO::PARAM_INT
-            );
+            ];
         }
 
         $sql .= implode(" OR ", $whereOr);
@@ -297,7 +291,7 @@ public function getMembershipIdsByGroupIds($groupIds)
 
         // bind search values
         foreach ($binds as $var => $bind) {
-            $Stmt->bindValue(':' . $var, $bind['value'], $bind['type']);
+            $Stmt->bindValue(':'.$var, $bind['value'], $bind['type']);
         }
 
         try {
@@ -305,7 +299,7 @@ public function getMembershipIdsByGroupIds($groupIds)
             $result = $Stmt->fetchAll(\PDO::FETCH_ASSOC);
         } catch (\Exception $Exception) {
             QUI\System\Log::writeException($Exception);
-            return array();
+            return [];
         }
 
         foreach ($result as $row) {
@@ -347,7 +341,7 @@ public static function getProductCategory()
             return ProductCategories::getCategory((int)$categoryId);
         } catch (\Exception $Exception) {
             if ($Exception->getCode() !== 404) {
-                QUI\System\Log::addError(self::class . ' :: getProductCategory()');
+                QUI\System\Log::addError(self::class.' :: getProductCategory()');
                 QUI\System\Log::writeException($Exception);
             }
 
@@ -369,11 +363,16 @@ public static function getProductMembershipField()
         }
 
         try {
-            return ProductFields::getField(self::PRODUCTS_FIELD_MEMBERSHIP);
+            $Conf    = QUI::getPackage('quiqqer/memberships')->getConfig();
+            $fieldId = $Conf->get('products', 'membershipFieldId');
+
+            if (empty($fieldId)) {
+                return false;
+            }
+
+            return ProductFields::getField($fieldId);
         } catch (\Exception $Exception) {
-            QUI\System\Log::addError(self::class . ' :: getProductMembershipField()');
             QUI\System\Log::writeException($Exception);
-
             return false;
         }
     }
@@ -392,11 +391,16 @@ public static function getProductMembershipFlagField()
         }
 
         try {
-            return ProductFields::getField(self::PRODUCTS_FIELD_MEMBERSHIPFLAG);
+            $Conf    = QUI::getPackage('quiqqer/memberships')->getConfig();
+            $fieldId = $Conf->get('products', 'membershipFlagFieldId');
+
+            if (empty($fieldId)) {
+                return false;
+            }
+
+            return ProductFields::getField($fieldId);
         } catch (\Exception $Exception) {
-            QUI\System\Log::addError(self::class . ' :: getProductMembershipFlagField()');
             QUI\System\Log::writeException($Exception);
-
             return false;
         }
     }
diff --git a/src/QUI/Memberships/Membership.php b/src/QUI/Memberships/Membership.php
index f86c83facc99b9b1f927fb50577b1911d47b01e2..8739df52a44cb5f095228b3277532ed781726971 100644
--- a/src/QUI/Memberships/Membership.php
+++ b/src/QUI/Memberships/Membership.php
@@ -114,13 +114,13 @@ public function update()
         // check groups
         if (empty($attributes['groupIds'])
         ) {
-            throw new QUI\Memberships\Exception(array(
+            throw new QUI\Memberships\Exception([
                 'quiqqer/memberships',
                 'exception.handler.no.groups'
-            ));
+            ]);
         }
 
-        $attributes['groupIds'] = ',' . $attributes['groupIds'] . ',';
+        $attributes['groupIds'] = ','.$attributes['groupIds'].',';
 
         // check duration
         if (empty($attributes['duration'])
@@ -131,10 +131,10 @@ public function update()
             $duration = explode('-', $attributes['duration']);
 
             if ($duration[0] < 1) {
-                throw new QUI\Memberships\Exception(array(
+                throw new QUI\Memberships\Exception([
                     'quiqqer/memberships',
                     'exception.membership.update.duration.invalid'
-                ));
+                ]);
             }
         }
 
@@ -150,10 +150,12 @@ public function update()
     /**
      * Delete membership
      *
-     * Only possible if membership has no users in it
+     * Only possible if membership has no users in it!
      *
      * @return void
-     * @throws QUI\Memberships\Exception
+     * @throws \QUI\Memberships\Exception
+     * @throws \QUI\Permissions\Exception
+     * @throws \QUI\Exception
      */
     public function delete()
     {
@@ -162,10 +164,10 @@ public function delete()
         $MembershipUsers = MembershipUsersHandler::getInstance();
 
         if (count($MembershipUsers->getIdsByMembershipId($this->id))) {
-            throw new Exception(array(
+            throw new Exception([
                 'quiqqer/memberships',
                 'exception.membership.cannot.delete.with.users.left'
-            ));
+            ]);
         }
 
         if ($this->isDefault()) {
@@ -178,8 +180,16 @@ public function delete()
         if (Utils::isQuiqqerProductsInstalled()) {
             /** @var QUI\ERP\Products\Product\Product $Product */
             foreach ($this->getProducts() as $Product) {
-                $MembershipField = $Product->getField(Handler::PRODUCTS_FIELD_MEMBERSHIP);
+                $MembershipField = $Product->getField(
+                    Handler::getProductMembershipField()->getId()
+                );
                 $MembershipField->setValue(null);
+
+                $MembershipFlagField = $Product->getField(
+                    Handler::getProductMembershipFlagField()->getId()
+                );
+                $MembershipFlagField->setValue(null);
+
                 $Product->deactivate();
                 $Product->save();
             }
@@ -201,26 +211,26 @@ public function delete()
      */
     public function getMembershipUser($userId)
     {
-        $result = QUI::getDataBase()->fetch(array(
-            'select' => array(
+        $result = QUI::getDataBase()->fetch([
+            'select' => [
                 'id'
-            ),
+            ],
             'from'   => MembershipUsersHandler::getInstance()->getDataBaseTableName(),
-            'where'  => array(
+            'where'  => [
                 'membershipId' => $this->id,
                 'userId'       => $userId,
                 'archived'     => 0
-            )
-        ));
+            ]
+        ]);
 
         if (empty($result)) {
-            throw new Exception(array(
+            throw new Exception([
                 'quiqqer/memberships',
                 'exception.membership.user.not.found',
-                array(
+                [
                     'userId' => $userId
-                )
-            ), 404);
+                ]
+            ], 404);
         }
 
         return MembershipUsersHandler::getInstance()->getChild($result[0]['id']);
@@ -266,18 +276,18 @@ public function getUniqueGroupIds()
      */
     public function hasMembershipUserId($userId)
     {
-        $result = QUI::getDataBase()->fetch(array(
+        $result = QUI::getDataBase()->fetch([
             'count'  => 1,
-            'select' => array(
+            'select' => [
                 'id'
-            ),
+            ],
             'from'   => MembershipUsersHandler::getInstance()->getDataBaseTableName(),
-            'where'  => array(
+            'where'  => [
                 'membershipId' => $this->id,
                 'userId'       => $userId,
                 'archived'     => 0
-            )
-        ));
+            ]
+        ]);
 
         return current(current($result)) > 0;
     }
@@ -292,13 +302,13 @@ public function hasMembershipUserId($userId)
      */
     public function searchUsers($searchParams, $archivedOnly = false, $countOnly = false)
     {
-        $membershipUserIds = array();
+        $membershipUserIds = [];
         $Grid              = new QUI\Utils\Grid($searchParams);
         $gridParams        = $Grid->parseDBParams($searchParams);
         $tbl               = MembershipUsersHandler::getInstance()->getDataBaseTableName();
         $usersTbl          = QUI::getDBTableName('users');
-        $binds             = array();
-        $where             = array();
+        $binds             = [];
+        $where             = [];
 
         if ($countOnly) {
             $sql = "SELECT COUNT(*)";
@@ -306,10 +316,10 @@ public function searchUsers($searchParams, $archivedOnly = false, $countOnly = f
             $sql = "SELECT `musers`.id";
         }
 
-        $sql .= " FROM `" . $tbl . "` musers, `" . $usersTbl . "` users";
+        $sql .= " FROM `".$tbl."` musers, `".$usersTbl."` users";
 
         $where[] = '`musers`.userId = `users`.id';
-        $where[] = '`musers`.membershipId = ' . $this->id;
+        $where[] = '`musers`.membershipId = '.$this->id;
 
         if ($archivedOnly === false) {
             $where[] = '`musers`.archived = 0';
@@ -318,36 +328,36 @@ public function searchUsers($searchParams, $archivedOnly = false, $countOnly = f
         }
 
         if (!empty($searchParams['search'])) {
-            $whereOR = array();
+            $whereOR = [];
 
-            $searchColumns = array(
+            $searchColumns = [
                 '`users`.username',
                 '`users`.firstname',
                 '`users`.lastname'
-            );
+            ];
 
             foreach ($searchColumns as $tbl => $column) {
-                $whereOR[]       = $column . ' LIKE :search';
-                $binds['search'] = array(
-                    'value' => '%' . $searchParams['search'] . '%',
+                $whereOR[]       = $column.' LIKE :search';
+                $binds['search'] = [
+                    'value' => '%'.$searchParams['search'].'%',
                     'type'  => \PDO::PARAM_STR
-                );
+                ];
             }
 
-            $where[] = '(' . implode(' OR ', $whereOR) . ')';
+            $where[] = '('.implode(' OR ', $whereOR).')';
         }
 
         if (!empty($searchParams['productId'])) {
             $where[]            = '`musers`.productId = :productId';
-            $binds['productId'] = array(
+            $binds['productId'] = [
                 'value' => (int)$searchParams['productId'],
                 'type'  => \PDO::PARAM_INT
-            );
+            ];
         }
 
         // build WHERE query string
         if (!empty($where)) {
-            $sql .= " WHERE " . implode(" AND ", $where);
+            $sql .= " WHERE ".implode(" AND ", $where);
         }
 
         // ORDER
@@ -359,34 +369,34 @@ public function searchUsers($searchParams, $archivedOnly = false, $countOnly = f
                 case 'username':
                 case 'firstname':
                 case 'lastname':
-                    $sortOn = '`users`.' . $sortOn;
+                    $sortOn = '`users`.'.$sortOn;
                     break;
 
                 default:
-                    $sortOn = '`musers`.' . $sortOn;
+                    $sortOn = '`musers`.'.$sortOn;
             }
 
-            $order = "ORDER BY " . $sortOn;
+            $order = "ORDER BY ".$sortOn;
 
             if (isset($searchParams['sortBy']) &&
                 !empty($searchParams['sortBy'])
             ) {
-                $order .= " " . Orthos::clear($searchParams['sortBy']);
+                $order .= " ".Orthos::clear($searchParams['sortBy']);
             } else {
                 $order .= " ASC";
             }
 
-            $sql .= " " . $order;
+            $sql .= " ".$order;
         }
 
         // LIMIT
         if (!empty($gridParams['limit'])
             && !$countOnly
         ) {
-            $sql .= " LIMIT " . $gridParams['limit'];
+            $sql .= " LIMIT ".$gridParams['limit'];
         } else {
             if (!$countOnly) {
-                $sql .= " LIMIT " . (int)20;
+                $sql .= " LIMIT ".(int)20;
             }
         }
 
@@ -394,7 +404,7 @@ public function searchUsers($searchParams, $archivedOnly = false, $countOnly = f
 
         // bind search values
         foreach ($binds as $var => $bind) {
-            $Stmt->bindValue(':' . $var, $bind['value'], $bind['type']);
+            $Stmt->bindValue(':'.$var, $bind['value'], $bind['type']);
         }
 
         try {
@@ -402,10 +412,10 @@ public function searchUsers($searchParams, $archivedOnly = false, $countOnly = f
             $result = $Stmt->fetchAll(\PDO::FETCH_ASSOC);
         } catch (\Exception $Exception) {
             QUI\System\Log::addError(
-                self::class . ' :: searchUsers() -> ' . $Exception->getMessage()
+                self::class.' :: searchUsers() -> '.$Exception->getMessage()
             );
 
-            return array();
+            return [];
         }
 
         if ($countOnly) {
@@ -445,13 +455,13 @@ public function calcEndDate($start = null)
 
         switch ($durationMode) {
             case 'day':
-                $endTime    = strtotime($start . ' +' . $durationCount . ' ' . $durationScope);
+                $endTime    = strtotime($start.' +'.$durationCount.' '.$durationScope);
                 $beginOfDay = strtotime("midnight", $endTime);
                 $end        = strtotime("tomorrow", $beginOfDay) - 1;
                 break;
 
             default:
-                $end = strtotime($start . ' +' . $durationCount . ' ' . $durationScope);
+                $end = strtotime($start.' +'.$durationCount.' '.$durationScope);
         }
 
         return Utils::getFormattedTimestamp($end);
@@ -467,25 +477,35 @@ public function calcEndDate($start = null)
     public function getProducts()
     {
         if (!Utils::isQuiqqerProductsInstalled()) {
-            return array();
+            return [];
         }
 
-        $Search = new BackendSearch();
-
         try {
-            $result = $Search->search(array(
-                'fields' => array(
-                    Handler::PRODUCTS_FIELD_MEMBERSHIP => "$this->id" // has to be string
-                )
-            ));
-        } catch (QUI\Permissions\Exception $Exception) {
-            return array();
+            $Search          = new BackendSearch();
+            $MembershipField = Handler::getProductMembershipField();
+
+            if ($MembershipField === false) {
+                return [];
+            }
+
+            $result = $Search->search([
+                'fields' => [
+                    $MembershipField->getId() => "$this->id" // has to be string
+                ]
+            ]);
+        } catch (\Exception $Exception) {
+            QUI\System\Log::writeException($Exception);
+            return [];
         }
 
-        $products = array();
+        $products = [];
 
         foreach ($result as $id) {
-            $products[] = ProductsHandler::getProduct($id);
+            try {
+                $products[] = ProductsHandler::getProduct($id);
+            } catch (\Exception $Exception) {
+                QUI\System\Log::writeException($Exception);
+            }
         }
 
         return $products;
@@ -507,8 +527,8 @@ public function createProduct()
             return false;
         }
 
-        $categories = array();
-        $fields     = array();
+        $categories = [];
+        $fields     = [];
 
         $Category = Handler::getProductCategory();
 
@@ -598,7 +618,7 @@ public function isLocked()
      */
     protected function getLockKey()
     {
-        return 'membership_' . $this->id;
+        return 'membership_'.$this->id;
     }
 
     /**
@@ -608,12 +628,12 @@ protected function getLockKey()
      */
     public function getBackendViewData()
     {
-        return array(
+        return [
             'id'          => $this->getId(),
             'title'       => $this->getTitle(),
             'description' => $this->getDescription(),
             'content'     => $this->getContent()
-        );
+        ];
     }
 
     /**
@@ -650,9 +670,9 @@ public function isDefault()
      */
     public function addUser(QUI\Users\User $User)
     {
-        return MembershipUsersHandler::getInstance()->createChild(array(
+        return MembershipUsersHandler::getInstance()->createChild([
             'userId'       => $User->getId(),
             'membershipId' => $this->id
-        ));
+        ]);
     }
 }
diff --git a/src/QUI/Memberships/Users/AbortCancelVerification.php b/src/QUI/Memberships/Users/AbortCancelVerification.php
index 5e8ff8bc01a4f8184c5c7cba2c72a46f0e4d6689..3efc636f02b6dc154029dbe989089dd292ac9d97 100644
--- a/src/QUI/Memberships/Users/AbortCancelVerification.php
+++ b/src/QUI/Memberships/Users/AbortCancelVerification.php
@@ -18,6 +18,7 @@ class AbortCancelVerification extends QUI\Verification\AbstractVerification
      *
      * @return int|false - duration in minutes;
      * if this method returns false use the module setting default value
+     * @throws \QUI\Exception
      */
     public function getValidDuration()
     {
@@ -33,6 +34,7 @@ public function getValidDuration()
      * Execute this method on successful verification
      *
      * @return void
+     * @throws \QUI\Exception
      */
     public function onSuccess()
     {
@@ -55,28 +57,32 @@ public function onError()
      * This message is displayed to the user on successful verification
      *
      * @return string
+     * @throws \QUI\Exception
      */
     public function getSuccessMessage()
     {
         /** @var MembershipUser $MembershipUser */
         $MembershipUser = MembershipUsersHandler::getInstance()->getChild($this->getIdentifier());
+        $Membership     = $MembershipUser->getMembership();
         $data           = $MembershipUser->getFrontendViewData();
 
-        if ($MembershipUser->getMembership()->isAutoExtend()) {
+        if ($Membership->isAutoExtend()) {
             $msg = QUI::getLocale()->get(
                 'quiqqer/memberships',
                 'verification.abortcancel.success.autoExtend',
-                array(
-                    'endDate' => $data['endDate']
-                )
+                [
+                    'endDate'         => $data['endDate'],
+                    'membershipTitle' => $Membership->getTitle()
+                ]
             );
         } else {
             $msg = QUI::getLocale()->get(
                 'quiqqer/memberships',
                 'verification.abortcancel.success.noAutoExtend',
-                array(
-                    'endDate' => $data['endDate']
-                )
+                [
+                    'endDate'         => $data['endDate'],
+                    'membershipTitle' => $Membership->getTitle()
+                ]
             );
         }
 
diff --git a/src/QUI/Memberships/Users/MembershipUser.php b/src/QUI/Memberships/Users/MembershipUser.php
index 0293b56bedfd824f2e646f33698a33a937fb0b47..86a85b1c5fda4b48b3cfcecb4d6696c1a2e41e18 100644
--- a/src/QUI/Memberships/Users/MembershipUser.php
+++ b/src/QUI/Memberships/Users/MembershipUser.php
@@ -475,6 +475,7 @@ public function getUserId()
      * Get QUIQQER User
      *
      * @return QUI\Users\User
+     * @throws \QUI\Exception
      */
     public function getUser()
     {
@@ -534,6 +535,7 @@ public function getHistory()
      *
      * @param string $date - Formatted date YYYY-MM-DD HH:MM:SS
      * @return string|false - formatted date or false on error
+     * @throws \QUI\Exception
      */
     protected function formatDate($date)
     {