diff --git a/app/assets/javascripts/admin/controllers/admin-backups-index.js.es6 b/app/assets/javascripts/admin/controllers/admin-backups-index.js.es6
index a7ecd0c30..c3ade201b 100644
--- a/app/assets/javascripts/admin/controllers/admin-backups-index.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-backups-index.js.es6
@@ -28,11 +28,11 @@ export default Ember.ArrayController.extend({
     }
   }.property("status.isOperationRunning"),
 
-  readOnlyModeTitle: function() { return this._readOnlyModeI18n("title"); }.property("Discourse.isReadOnly"),
-  readOnlyModeText: function() { return this._readOnlyModeI18n("text"); }.property("Discourse.isReadOnly"),
+  readOnlyModeTitle: function() { return this._readOnlyModeI18n("title"); }.property("site.isReadOnly"),
+  readOnlyModeText: function() { return this._readOnlyModeI18n("text"); }.property("site.isReadOnly"),
 
   _readOnlyModeI18n: function(value) {
-    var action = Discourse.get("isReadOnly") ? "disable" : "enable";
+    var action = this.site.get("isReadOnly") ? "disable" : "enable";
     return I18n.t("admin.backups.read_only." + action + "." + value);
   },
 
@@ -45,7 +45,7 @@ export default Ember.ArrayController.extend({
     **/
     toggleReadOnlyMode: function() {
       var self = this;
-      if (!Discourse.get("isReadOnly")) {
+      if (!this.site.get("isReadOnly")) {
         bootbox.confirm(
           I18n.t("admin.backups.read_only.enable.confirm"),
           I18n.t("no_value"),
@@ -65,11 +65,12 @@ export default Ember.ArrayController.extend({
   },
 
   _toggleReadOnlyMode: function(enable) {
+    var site = this.site;
     Discourse.ajax("/admin/backups/readonly", {
       type: "PUT",
       data: { enable: enable }
     }).then(function() {
-      Discourse.set("isReadOnly", enable);
+      site.set("isReadOnly", enable);
     });
   }
 });
diff --git a/app/assets/javascripts/admin/templates/admin.js.handlebars b/app/assets/javascripts/admin/templates/admin.js.handlebars
index 85a695066..7ef0ed1c5 100644
--- a/app/assets/javascripts/admin/templates/admin.js.handlebars
+++ b/app/assets/javascripts/admin/templates/admin.js.handlebars
@@ -1,5 +1,5 @@
 <div class="container">
-  {{Discourse.globalNotice}}
+  {{global-notice}}
   <div class="row">
     <div class="full-width">
 
diff --git a/app/assets/javascripts/discourse.js b/app/assets/javascripts/discourse.js
index 8f8b1ff18..dfaa06172 100644
--- a/app/assets/javascripts/discourse.js
+++ b/app/assets/javascripts/discourse.js
@@ -132,38 +132,6 @@ window.Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
       }
     }
     return this.get("currentAssetVersion");
-  }.property(),
-
-  globalNotice: function(){
-    var notices = [];
-
-    if(this.get("isReadOnly")){
-      notices.push(I18n.t("read_only_mode.enabled"));
-    }
-
-    if(Discourse.User.currentProp('admin') && Discourse.SiteSettings.show_create_topics_notice) {
-      var topic_count = 0,
-          post_count = 0;
-      _.each(Discourse.Site.currentProp('categories'), function(c) {
-        if (!c.get('read_restricted')) {
-          topic_count += c.get('topic_count');
-          post_count  += c.get('post_count');
-        }
-      });
-      if (topic_count < 5 || post_count < Discourse.SiteSettings.tl1_requires_read_posts) {
-        notices.push(I18n.t("too_few_topics_notice", {posts: Discourse.SiteSettings.tl1_requires_read_posts}));
-      }
-    }
-
-    if(!_.isEmpty(Discourse.SiteSettings.global_notice)){
-      notices.push(Discourse.SiteSettings.global_notice);
-    }
-
-    if(notices.length > 0) {
-      return new Handlebars.SafeString(_.map(notices, function(text) {
-        return "<div class='row'><div class='alert alert-info'>" + text + "</div></div>";
-      }).join(""));
-    }
-  }.property("isReadOnly")
+  }.property()
 
 });
diff --git a/app/assets/javascripts/discourse/components/global-notice.js.es6 b/app/assets/javascripts/discourse/components/global-notice.js.es6
new file mode 100644
index 000000000..7dca11a0c
--- /dev/null
+++ b/app/assets/javascripts/discourse/components/global-notice.js.es6
@@ -0,0 +1,36 @@
+export default Ember.Component.extend({
+
+  shouldRerender: Discourse.View.renderIfChanged("site.isReadOnly"),
+
+  render: function(buffer) {
+    var notices = [];
+
+    if (this.site.get("isReadOnly")) {
+      notices.push(I18n.t("read_only_mode.enabled"));
+    }
+
+    if (Discourse.User.currentProp('admin') && this.siteSettings.show_create_topics_notice) {
+      var topic_count = 0,
+          post_count = 0;
+      _.each(this.site.get('categories'), function(c) {
+        if (!c.get('read_restricted')) {
+          topic_count += c.get('topic_count');
+          post_count  += c.get('post_count');
+        }
+      });
+      if (topic_count < 5 || post_count < this.siteSettings.tl1_requires_read_posts) {
+        notices.push(I18n.t("too_few_topics_notice", {posts: this.siteSettings.tl1_requires_read_posts}));
+      }
+    }
+
+    if (!_.isEmpty(this.siteSettings.global_notice)) {
+      notices.push(this.siteSettings.global_notice);
+    }
+
+    if (notices.length > 0) {
+      buffer.push(_.map(notices, function(text) {
+        return "<div class='row'><div class='alert alert-info'>" + text + "</div></div>";
+      }).join(""));
+    }
+  }
+});
diff --git a/app/assets/javascripts/discourse/initializers/inject-app-events.js.es6 b/app/assets/javascripts/discourse/initializers/inject-app-events.js.es6
index ea701a677..aa412adc7 100644
--- a/app/assets/javascripts/discourse/initializers/inject-app-events.js.es6
+++ b/app/assets/javascripts/discourse/initializers/inject-app-events.js.es6
@@ -1,6 +1,8 @@
 export default {
-  name: "inject-app-events",
+  name: "inject-objects",
   initialize: function(container, application) {
+
+    // Inject appEvents everywhere
     var appEvents = Ember.Object.createWithMixins(Ember.Evented);
     application.register('app-events:main', appEvents, { instantiate: false });
 
@@ -9,7 +11,23 @@ export default {
     application.inject('route', 'appEvents', 'app-events:main');
     application.inject('view', 'appEvents', 'app-events:main');
     application.inject('model', 'appEvents', 'app-events:main');
-
     Discourse.URL.appEvents = appEvents;
+
+    // Inject Discourse.Site to avoid using Discourse.Site.current()
+    var site = Discourse.Site.current();
+    application.register('site:main', site, { instantiate: false });
+    application.inject('controller', 'site', 'site:main');
+    application.inject('component', 'site', 'site:main');
+    application.inject('route', 'site', 'site:main');
+    application.inject('view', 'site', 'site:main');
+    application.inject('model', 'site', 'site:main');
+
+    // Inject Discourse.SiteSettings to avoid using Discourse.SiteSettings globals
+    application.register('site-settings:main', Discourse.SiteSettings, { instantiate: false });
+    application.inject('controller', 'siteSettings', 'site-settings:main');
+    application.inject('component', 'siteSettings', 'site-settings:main');
+    application.inject('route', 'siteSettings', 'site-settings:main');
+    application.inject('view', 'siteSettings', 'site-settings:main');
+    application.inject('model', 'siteSettings', 'site-settings:main');
   }
 };
diff --git a/app/assets/javascripts/discourse/initializers/inject-objects.js.es6 b/app/assets/javascripts/discourse/initializers/inject-objects.js.es6
new file mode 100644
index 000000000..ea701a677
--- /dev/null
+++ b/app/assets/javascripts/discourse/initializers/inject-objects.js.es6
@@ -0,0 +1,15 @@
+export default {
+  name: "inject-app-events",
+  initialize: function(container, application) {
+    var appEvents = Ember.Object.createWithMixins(Ember.Evented);
+    application.register('app-events:main', appEvents, { instantiate: false });
+
+    application.inject('controller', 'appEvents', 'app-events:main');
+    application.inject('component', 'appEvents', 'app-events:main');
+    application.inject('route', 'appEvents', 'app-events:main');
+    application.inject('view', 'appEvents', 'app-events:main');
+    application.inject('model', 'appEvents', 'app-events:main');
+
+    Discourse.URL.appEvents = appEvents;
+  }
+};
diff --git a/app/assets/javascripts/discourse/initializers/read-only.js.es6 b/app/assets/javascripts/discourse/initializers/read-only.js.es6
index 0b99766b5..83a4f61e6 100644
--- a/app/assets/javascripts/discourse/initializers/read-only.js.es6
+++ b/app/assets/javascripts/discourse/initializers/read-only.js.es6
@@ -6,13 +6,10 @@ export default {
   after: "message-bus",
 
   initialize: function () {
-    // initialize read-only mode and subscribe to updates via the message bus
-    Discourse.set("isReadOnly", Discourse.Site.currentProp("is_readonly"));
-
     if (!Discourse.MessageBus) { return; }
 
     Discourse.MessageBus.subscribe("/site/read-only", function (enabled) {
-      Discourse.set("isReadOnly", enabled);
+      Discourse.Site.currentProp('isReadOnly', enabled);
     });
   }
 };
diff --git a/app/assets/javascripts/discourse/models/site.js b/app/assets/javascripts/discourse/models/site.js
index 3b8eba082..fd6868613 100644
--- a/app/assets/javascripts/discourse/models/site.js
+++ b/app/assets/javascripts/discourse/models/site.js
@@ -8,6 +8,8 @@
 **/
 Discourse.Site = Discourse.Model.extend({
 
+  isReadOnly: Em.computed.alias('is_readonly'),
+
   notificationLookup: function() {
     var result = [];
     _.each(this.get('notification_types'), function(v,k) {
diff --git a/app/assets/javascripts/discourse/routes/application.js.es6 b/app/assets/javascripts/discourse/routes/application.js.es6
index cba09eb3e..bf0f8078b 100644
--- a/app/assets/javascripts/discourse/routes/application.js.es6
+++ b/app/assets/javascripts/discourse/routes/application.js.es6
@@ -41,7 +41,7 @@ var ApplicationRoute = Em.Route.extend({
     showLogin: function() {
       var self = this;
 
-      if (Discourse.get("isReadOnly")) {
+      if (this.site.get("isReadOnly")) {
         bootbox.alert(I18n.t("read_only_mode.login_disabled"));
       } else {
         if(Discourse.SiteSettings.enable_sso) {
diff --git a/app/assets/javascripts/discourse/templates/discovery.js.handlebars b/app/assets/javascripts/discourse/templates/discovery.js.handlebars
index c4ba98bed..8b1c7cbbf 100644
--- a/app/assets/javascripts/discourse/templates/discovery.js.handlebars
+++ b/app/assets/javascripts/discourse/templates/discovery.js.handlebars
@@ -1,6 +1,6 @@
 <div class='container'>
   {{custom-html "top"}}
-  {{Discourse.globalNotice}}
+  {{global-notice}}
   {{discourse-banner user=currentUser banner=Discourse.banner}}
 </div>
 
diff --git a/app/assets/javascripts/discourse/templates/topic.js.handlebars b/app/assets/javascripts/discourse/templates/topic.js.handlebars
index c459749ea..86059cb0c 100644
--- a/app/assets/javascripts/discourse/templates/topic.js.handlebars
+++ b/app/assets/javascripts/discourse/templates/topic.js.handlebars
@@ -1,6 +1,6 @@
 <div class='container'>
   {{custom-html "top"}}
-  {{Discourse.globalNotice}}
+  {{global-notice}}
   {{discourse-banner user=currentUser banner=Discourse.banner overlay=view.hasScrolled}}
 </div>
 
diff --git a/app/assets/javascripts/discourse/templates/user/user.js.handlebars b/app/assets/javascripts/discourse/templates/user/user.js.handlebars
index 8435fbce0..bf4120fd1 100644
--- a/app/assets/javascripts/discourse/templates/user/user.js.handlebars
+++ b/app/assets/javascripts/discourse/templates/user/user.js.handlebars
@@ -1,6 +1,6 @@
 <div class='container'>
   {{custom-html "top"}}
-  {{Discourse.globalNotice}}
+  {{global-notice}}
 </div>
 
 {{#unless loading}}