RWKit Changes in RW9

Hey guys,

As you’ve probably guessed, I’ve been tidying up the API in RW9. The API has existed since the very beginning and as such has accumulated a lot of cruft, bad practices and duplicated functionality over the years. Trying to maintain everything in the API has become an impossible task and severally limits the new features I can add.

I’m routing through the API and will keep this post updated with the latest information on changes and removals, along with plugins that could be affected where possible. In many cases, fixing your plugin will simply be a case of removing the method/reference.

If your plugin requires anything mentioned here, let me know ASAP.


Public API Changes

Undeclared methods

REMOVED - populatePluginSettings:

@protocol RWPluginEditing
REMOVED - (id)valueForThemeSpecificOptionKey:(NSString *)key;
REMOVED - (void)setValue:(id)value forThemeSpecificOptionKey:(NSString *)key;

Plugins affected Flow

REMOVED @protocol RWPluginSettings
REMOVED - (NSDictionary *)pluginSettings;
REMOVED - (void)setPluginSettings:(NSDictionary *)settings;
REMOVED - (BOOL)acceptsPluginSettings:(NSDictionary *)settings;
REMOVED - (BOOL)providesPluginSettings;

Plugins affected Flow

Defined in RWPluginExport
REMOVED extern NSString *const kRWExporterPageExportDidStart;
REMOVED extern NSString *const kRWExporterPageExportDidEnd;

Plugins affected RapidCartPro

Defined in RWAbstractPlugin
REMOVED - (NSString *)registerFileURL:(NSURL *)fileURL error:(NSError **)error;
REMOVED - (void)removeFileReferenceForToken:(NSString *)token;
REMOVED - (NSURL *)fileURLForToken:(NSString *)token error:(NSError **)error;

Plugins affected Hard to tell, possibly Stacks, FormLoom, PayLoom but I think they’re fine.

REMOVED @protocol RWPluginSettingsViewController
REMOVED - (NSViewController *)settingsViewController;

Plugins affected None

Defined in @protocol RWPluginArchiving
REMOVED - (NSString *)archivingName;
REMOVED - (NSString *)archivingAuthor;
REMOVED - (NSURL *)archivingHomepageURL;
REMOVED - (NSString *)archivingClassName;
REMOVED - (NSData *)archivingData;

Plugins affected None

Defined in RWPluginExport
REMOVED - (NSArray <NSString *> *)pagesForSiteMap:(NSDictionary *)info;
REMOVED - (RMHTMLPackage *)renderForPage:(RWExportParameters *)exportParameters;

Plugins affected None

Defined in RWAbstractPlugin
REMOVED extern NSString* const kRWPluginStartedLoadingNotification;
REMOVED extern NSString* const kRWPluginFinishedLoadingNotification;
REMOVED extern NSString* const kRWPluginStartedMigrationNotification;
REMOVED extern NSString* const kRWPluginFinishedMigrationNotification;
REMOVED extern NSString *const kRWPluginChangedNotification;
REMOVED extern NSString *const kRWPluginChangedInvertNotification;
REMOVED extern NSString *const kRWPluginExportStatusNotification;
REMOVED extern NSString *const kRWCurrentMediaChangedNotification;
REMOVED extern NSString *const kRWPluginPageSettingsRequestNotification;
REMOVED extern NSString *const kRWDoubleClickedMediaNotification;
REMOVED extern NSString *const kRWPluginChangedReloadPreviewUserInfoKey;
REMOVED enum {
Defined in RWAbstractPlugin
REMOVED - (void)broadcastPluginChangedReloadingPreviews:(BOOL)reloadPreview;
REMOVED + (NSString *)tempFilesDirectory:(NSString *)name forPlugin:(RWAbstractPlugin *)plugin;
REMOVED + (NSString *)tempFilesDirectory:(NSString *)name forUniqueID:(NSString *)unique;
REMOVED + (NSString *)pathToTempDirectory;
REMOVED + (NSString *)pathToAppTempDirectory;
REMOVED - (NSMutableDictionary *)contentOnlySubpageWithHTML:(NSString *)content name:(NSString *)name;
REMOVED - (NSMutableDictionary *)contentOnlySubpageWithData:(NSData *)content name:(NSString *)name;
REMOVED - (NSMutableDictionary *)contentOnlySubpageWithEntireHTML:(NSString *)content name:(NSString *)name;
REMOVED - (NSMutableDictionary *)customSubpageWithData:(NSData *)content name:(NSString *)name destination:(NSString *)destination;
REMOVED - (NSMutableString *)updatePageTemplate:(NSMutableString *)pageTemplate params:(NSDictionary *)params depth:(NSInteger)depth;
REMOVED - (NSString *)pathToThemeFile:(NSString *)file params:(NSDictionary *)params correction:(NSInteger)depth;
REMOVED - (NSArray *)directoryContents:(NSString *)path;

Plugins affected FormLoom & PayLoom
please use
- (NSString *)tempFilesDirectory:(NSString *)name
instead of
+ (NSString *)pathToAppTempDirectory

Defined in RWPluginMetadata
REMOVED + (BOOL)hasHTMLDescription;
REMOVED + (NSString *)pluginVersion;
REMOVED + (NSImage *)addMenuPluginIcon;

Plugins affected None

UPDATED 2020/04/16

Public API Changes


Plugins affected Possibly Blocks & Collage 2
RWAlert provides no additional functionality over NSAlert. Use NSAlert instead.

The following classes have been removed as they are no longer used or provide no real benefit.

REMOVED RWExceptionName
REMOVED RWWebImageTransformationParameters

Plugins affected Unknown

Private API Changes

The following classes are private and so plugins shouldn’t be using them. They have been moved into RW or removed if no longer required.

REMOVED RWDocumentOptionsSnapshot
REMOVED RWDirectoryIndexEntry
REMOVED RWDocumentModel
REMOVED RWPageEncodings
REMOVED RWLegacySourceListNode
REMOVED RWLegacyResourceDatabase

Moved to RW

@interface NSMutableString (RWStyleSheet) 
@interface NSUserDefaults (RWKit)
@interface NSFileManager (RWKit)
@interface NSURL (Paths)
@interface NSString (Minify)

UPDATED 2020/04/20

Public API Changes


This class simply inherits RWCodeView and sets the language to HTML. Please use RWCodeView instead and set the language accordingly

[self.htmlView setLanguage:RWCodeHighlightingLanguageHTML];

Private API Changes

The Fragaria framework that powers RWCodeView has been moved to it’s own separate framework instead of being part of RWKit


when you mentioned (privately) that you were removing some stuff back in feb the conversation ended with me saying:

my only request is a reasonable deprecation period where both new and old API both work.

you didn’t happen to forget to mention a depcrecation period? replacement apis?


I’m really sorry but that’s not going to happen. Private classes are private for a reason, they are expected to change in the future and offer no guarantees of their existence. There isn’t a single platform out there that offers a deprecation period for private API’s. Apple doesn’t even allow apps on the App Store if they detect use of a private API.

By using private API’s it means I’m completely unable to do my job. I can’t refactor anything in RapidWeaver to allow for new features or fix bugs. Any change I make could bust a plugin, so my testing time is significantly increased.

I get that in the past there has been some confusion over public and private API’s but some of the private classes you’ve subclassed were only added in 2018 and have always been marked as private. If you opt to use private classes it’s up to you to fix it when your stuff breaks - and it will. It’s a ticking time bomb.

Now. I realise that a huge number of customers use your plugins and they need to be part of RW9. I’m absolutely willing to do what I can do to get your plugins up and running as quickly and as easily as possible but it’s not going to involve a deprecation period.

This really isn’t me trying to be mean, it’s actually technically impossible. Some of the private classes you’ve subclassed like RWSiteResource are now implemented as Swift classes in RW. Objective-C is unable so subclass a Swift class. Why the move to Swift? It offers some functionality that is critical to the future of RW.

The other problem that arrises if a deprecation period were to be offered is that classes like RWSiteResource are used in hundreds of places across RapidWeaver. I’d have to hold off updating any of those while the deprecation period exists. And then how long does the deprecation period last? That depends on much backwards compatibility the plugins need. Could be 1 or 2 versions right, that could stretch over 5 years.

With that said, let’s move on and talk about how we can fix things.

I have some idea’s on how to make your plugins work with RW9 and previous versions but you’re going to have to show me some code. I need to know what your subclasses do, what they implement and why. Maybe throw together a sample plugin with the private API’s in use that I can use for testing?

deprecation didn’t seem like a big ask. but whatever.

i added the stuff for site resources to stacks only just recently, at your direction, to build the Site Images feature of stacks.

without a replacement, how should i proceed?

Actually in October 2018 you were quite proud to tell us you reverse engineered the API

I had to reverse engineer the RW API from no docs and no help and somehow I (mostly) did it. But this resource API is TOUGH!!! It seems to be spread out over several different headers and each method I try seems to require a handful of other objects that I can’t find a way to get a reference to.

And my response at the time was the same as it is now

Please don’t do anymore work on this just yet. The API is incomplete with a number of private classes and will be changing.

Moving on…

There will be an official API for site resources in RW9 and I’d like to make it backwards compatible with RW8. I’m not sure if this is feasible purely from within RW because I have no idea what Stacks is doing.

To reiterate, I’m more than happy to spend as long as it takes to get Stacks and your other plugins working 100% in RW9 with minimal changes on your part but I need something to work from.

The first step is to get me a sample plugin that replicates your usage of the private API’s so I can attempt to figure something out.

If there’s anything missing in the API that’s critical to a plugin, I’ll either add it back in or open source the code.

Sound good?